ident = '$Id: editors.py 141 2006-08-01 19:15:43Z ahmad $'

# Survey editor
import sys, wx, wx.calendar, wx.html, rex, common, icon_manager, images, re, keywords, script_helper
import wx.stc	as stc
from xml.dom			import minidom
from xml.sax			import saxutils
from lang_keywords		import *

ID_INSTANCE_APPLY	= 20
ID_INSTANCE_UNAPPLY	= 21
ID_PUB_CUT			= 30
ID_PUB_PASTE		= 31


ID_HTML_CODEBOOK 	= 120
ID_TEXT_CODEBOOK 	= 121
ID_LABEL_BOOK		= 124

EDIT_KIND_TEXT		= 130
EDIT_KIND_HTML		= 131
EDIT_KIND_FILE		= 132
EDIT_KIND_EMAIL		= 133
EDIT_KIND_HTML_IS_HTML=134
EDIT_KIND_QUESTIONS	= 135
EDIT_KIND_NOTIFIERS	= 136

ID_OK				= 400
ID_CANCEL			= 401

ID_BODY_ENTRY		= 100
ID_SUBJECT_ENTRY 	= 101
ID_HTML_CHECKBOX	= 102
ID_EDITOR_LIST		= 103
ID_EDITOR_NEW_SAVE	= 105
ID_EDITOR_DELETE_CANCEL= 106
ID_EDITOR_DELETE	= 107
ID_ADDRESS_ENTRY	= 108
ID_EDITOR_QTYPE		= 109
ID_EDITOR_QUP		= 110
ID_EDITOR_QDOWN		= 111
ID_EDITOR_CUP		= 112
ID_EDITOR_CDOWN		= 113

ID_EDITOR_TRIGGER_SCROLL = 114
ID_EDITOR_LEVEL_SCROLL = 115

# SIMPLE_CONTACT_FORM_HEAD += "// Enter the correct group ID below or the word All\n"

SIMPLE_INSTANCE_LIST_HEAD  = "<# Start List;\n"
SIMPLE_INSTANCE_LIST_HEAD += "\\ rename the list to be unique within the page it is in."
SIMPLE_INSTANCE_LIST_HEAD += "\tnamed myList;\n"
SIMPLE_INSTANCE_LIST_HEAD += "\tFor Instances of Binder ( __bid__ );\n\tAs Frameless;\n\n"
SIMPLE_INSTANCE_LIST_HEAD += "COLUMNS\n"
SIMPLE_INSTANCE_LIST_VAR_LIST_BEGIN = "\tinstance.Instance_Name,\n\tinstance.Instance_ID"
SIMPLE_INSTANCE_LIST_VAR_LIST_ITEM = ",\n\tinstance.__vname__"
SIMPLE_INSTANCE_LIST_VAR_LIST_END = ";\n\n"
SIMPLE_INSTANCE_LIST_BODY  = "SORT BY\n"
SIMPLE_INSTANCE_LIST_BODY += "\tinstance.Instance_ID Ascending;\n\n"
SIMPLE_INSTANCE_LIST_BODY += "Show 40 rows per page. #>\n\n"
SIMPLE_INSTANCE_LIST_BODY += "<# open HEADER ROW template. #>\n"
SIMPLE_INSTANCE_LIST_BODY += "<table>\n"
SIMPLE_INSTANCE_LIST_BODY += "\t<tr>\n"
SIMPLE_INSTANCE_LIST_BODY += "\t\t<td>id</td>\n"
SIMPLE_INSTANCE_LIST_BODY += "\t\t<td>Instance Name</td>\n"
SIMPLE_INSTANCE_LIST_BODY_VAR = "\t\t<td>__vname__</td>\n"
SIMPLE_INSTANCE_LIST_BODY_END = "\t</tr>\n"
SIMPLE_INSTANCE_LIST_BODY_END += "<# close ROW template. #>\n\n"
SIMPLE_INSTANCE_LIST_BODY_END += "<# open BODY ROW template. #>\n"
SIMPLE_INSTANCE_LIST_BODY_END += "\t<tr>\n"
SIMPLE_INSTANCE_LIST_BODY_END += "\t\t<td>[instance.instance_id]</td>\n"
SIMPLE_INSTANCE_LIST_BODY_END += "\t\t<td>[instance.instance_name]</td>\n"
SIMPLE_INSTANCE_LIST_LIST_VAR = "\t\t<td>[instance.__vname__]</td>\n"
SIMPLE_INSTANCE_LIST_FOOT  = "\t</tr>\n"
SIMPLE_INSTANCE_LIST_FOOT += "<# close ROW template. #>\n\n"
SIMPLE_INSTANCE_LIST_FOOT += "<# open FOOTER ROW template. #>\n"
SIMPLE_INSTANCE_LIST_FOOT += "</table>\n"
SIMPLE_INSTANCE_LIST_FOOT += "<# close ROW template. #>\n\n"
SIMPLE_INSTANCE_LIST_FOOT += "<# open NO RESULTS message. #>\n\tNo results found.\n<# close message. #>\n"
SIMPLE_INSTANCE_LIST_FOOT += "<# End List. #>\n"

SIMPLE_CONTACT_LIST_HEAD  = "<# Start List;\n"
SIMPLE_CONTACT_LIST_HEAD += "\\\\ change the list name to be unique within the page it is in.\n"
SIMPLE_CONTACT_LIST_HEAD += "\tnamed myList;\n"
SIMPLE_CONTACT_LIST_HEAD += "\\\\ change the word \"all\" to a group id.\n"
SIMPLE_CONTACT_LIST_HEAD += "\tFor Contacts of Group ( all );\n\tAs Frameless;\n\n"
SIMPLE_CONTACT_LIST_HEAD += "COLUMNS\n"
SIMPLE_CONTACT_LIST_VAR_LIST_BEGIN = "\tcontact.id,\n\tcontact.uuid"
SIMPLE_CONTACT_LIST_VAR_LIST_ITEM = ",\n\tcontact.__vname__"
SIMPLE_CONTACT_LIST_VAR_LIST_END = ";\n\n"
SIMPLE_CONTACT_LIST_BODY  = "SORT BY\n"
SIMPLE_CONTACT_LIST_BODY += "\tcontact.Created_On Ascending;\n\n"
SIMPLE_CONTACT_LIST_BODY += "Show 40 rows per page. #>\n\n"
SIMPLE_CONTACT_LIST_BODY += "<# open HEADER ROW template. #>\n"
SIMPLE_CONTACT_LIST_BODY += "<table>\n"
SIMPLE_CONTACT_LIST_BODY += "\t<tr>\n"
SIMPLE_CONTACT_LIST_BODY += "\t\t<td>id</td>\n"
SIMPLE_CONTACT_LIST_BODY_VAR = "\t\t<td>__vname__</td>\n"
SIMPLE_CONTACT_LIST_BODY_END = "\t</tr>\n"
SIMPLE_CONTACT_LIST_BODY_END += "<# close ROW template. #>\n\n"
SIMPLE_CONTACT_LIST_BODY_END += "<# open BODY ROW template. #>\n"
SIMPLE_CONTACT_LIST_BODY_END += "\t<tr>\n"
SIMPLE_CONTACT_LIST_BODY_END += "\t\t<td>[contact.Id]</td>\n"
SIMPLE_CONTACT_LIST_LIST_VAR = "\t\t<td>[contact.__vname__]</td>\n"
SIMPLE_CONTACT_LIST_FOOT  = "\t</tr>\n"
SIMPLE_CONTACT_LIST_FOOT += "<# close ROW template. #>\n\n"
SIMPLE_CONTACT_LIST_FOOT += "<# open FOOTER ROW template. #>\n"
SIMPLE_CONTACT_LIST_FOOT += "</table>\n"
SIMPLE_CONTACT_LIST_FOOT += "<# close ROW template. #>\n\n"
SIMPLE_CONTACT_LIST_FOOT += "<# open NO RESULTS message. #>\n\tNo results found.\n<# close message. #>\n"
SIMPLE_CONTACT_LIST_FOOT += "<# End List. #>\n"


SIMPLE_INSTANCE_FORM_HEAD = "<# Start ServerForm;\n"
SIMPLE_INSTANCE_FORM_HEAD += "\tnamed __bname___serverform;\n"
SIMPLE_INSTANCE_FORM_HEAD += "\tFOR Instance ( __bid__.__iid__ );\n"
SIMPLE_INSTANCE_FORM_HEAD += ". #>\n\n"
SIMPLE_INSTANCE_FORM_HEAD += "Instance Name:<input type=\"text\" <# ATTACH ELEMENT( instance.__iname__ ). #> ><br>\n"
SIMPLE_INSTANCE_FORM_VAR_TEMPLATE = "<div>__vname__:</div>\n<div><input type=\"text\" <# ATTACH ELEMENT( instance.__vname__ ). #> ></div>\n"
SIMPLE_INSTANCE_FORM_FOOT = "<input type=\"button\" <# ATTACH UPDATE BUTTON. #> value=\"Update\" ><br>\n"
SIMPLE_INSTANCE_FORM_FOOT += "<input type=\"button\" <# ATTACH CREATE BUTTON. #> value=\"Create\" ><br>\n\n"
SIMPLE_INSTANCE_FORM_FOOT += "<div><# attach status. #></div>\n\n"
SIMPLE_INSTANCE_FORM_FOOT += "<# End Form. #>"

SIMPLE_CONTACT_FORM_HEAD = "<# Start ServerForm;\n"
SIMPLE_CONTACT_FORM_HEAD += "\tnamed __bname___serverform;\n"
SIMPLE_CONTACT_FORM_HEAD += "\tFOR Contact( !#[contact.id]#! );\n"
SIMPLE_CONTACT_FORM_HEAD += ". #>\n\n"
SIMPLE_CONTACT_FORM_VAR_TEMPLATE = "<div>__vname__:</div>\n<div><input type=\"text\"  <# ATTACH ELEMENT( contact.__vname__ ). #> ></div>\n"
SIMPLE_CONTACT_FORM_FOOT = "<input type=\"button\" <# ATTACH UPDATE BUTTON. #> value=\"Update\" ><br>\n"
SIMPLE_CONTACT_FORM_FOOT += "<input type=\"button\" <# ATTACH CREATE BUTTON. #> value=\"Create\" ><br>\n\n"
SIMPLE_CONTACT_FORM_FOOT += "<div><# attach status. #></div>\n\n"
SIMPLE_CONTACT_FORM_FOOT += "<# End Form. #>"

class text( stc.StyledTextCtrl ):
	def __init__( self, editor, parent=None ):
		common.dprint("Editor:", editor)
		common.dprint("Parent:", parent)
		if parent:
			common.dprint("text: Using suplied parent")
			stc.StyledTextCtrl.__init__( self, parent, -1 )
		else:
			common.dprint("text: Attempting to use the vSplitter")
			try:
				parent = editor.vSplitter
				common.dprint("text: OK")
			except:
				parent = editor
				common.show_error("Failed to find a vSplitter parent, usingn editor as the parent", False)
			stc.StyledTextCtrl.__init__( self, parent, -1 )
		# The top level sui object if any
		self.editor = editor
		# the current variable being edited
		self.var_id = None
		# lets go
		self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL )
				
		self.SetEOLMode( stc.STC_EOL_LF )
		self.SetMargins( 10, 0 )
		self.SetMarginType( 2, stc.STC_MARGIN_NUMBER )
		self.SetMarginSensitive( 2, True )
		self.SetMarginWidth( 2, 15 )
		self.SetBufferedDraw( 1 )
		self.SetEdgeMode( stc.STC_EDGE_LINE )
		self.SetEdgeColumn( 80 )
		self.SetKeyWords( 0, keywords.kw_tags )
		self.SetKeyWords( 1, keywords.kw_attribs )
		self.SetTabWidth( 4 )
		self.SetUseTabs( 1 )
		#self.SetViewWhiteSpace( 1 )
		self.SetTabIndents( 4 )
		self.SetIndent( 4 )
		self.SetIndentationGuides( True )
		self.SetCaretPeriod( 100 )
		self.SetCaretWidth( 4 )
		self.SetCaretForeground( "#FF5500" )
		self.SetStyleBits( 7 )
		self.set_hiliting( 'html' )
		# events
		self.Bind( wx.EVT_KEY_DOWN, self.OnKeyPressed)
		self.Bind( wx.EVT_KEY_UP, self.OnKeyUp)
		#self.Bind( wx.EVT_COMMAND_FIND, self.OnFind)
		#self.Bind( wx.EVT_COMMAND_FIND_NEXT, self.OnFind)
		#self.Bind( wx.EVT_COMMAND_FIND_REPLACE, self.OnFind)
		#self.Bind( wx.EVT_COMMAND_FIND_REPLACE_ALL, self.OnFind)
		#self.Bind( wx.EVT_COMMAND_FIND_CLOSE, self.OnFindClose)
		self.Bind( stc.EVT_STC_DRAG_OVER, self.OnDragOver )
        #self.Bind( stc.EVT_STC_DO_DROP( self, -1, self.OnDoDrop )
		self.Bind( stc.EVT_STC_CHANGE, self.OnChanged )
		# Use our own context menu
		self.UsePopUp( False )
		self.CreateContextMenu()
		self.Bind( wx.EVT_RIGHT_UP, self.OnMouseRightUp )
		self.wrap_text = False
		self.assign_keys()
		dt = text_drop_target( self, editor, "PUBLICATIONS" )
		self.SetDropTarget( dt )		

	def set_hiliting( self, kind ):
		if kind == 'html':
			self.SetLexer( stc.STC_LEX_HTML )
			self.StyleClearAll()
			common.dprint("Setting the font to %s %s" % (common.default_font_size, common.default_font_family ) ) 
			self.StyleSetSpec( stc.STC_STYLE_DEFAULT, "size:%s,face:%s" % (common.default_font_size, common.default_font_family ))
			
			self.StyleSetSpec( stc.STC_STYLE_LINENUMBER, "back:%s" % common.sui_colors("gray80") )
			self.StyleSetSpec( stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF, bold" )
			self.StyleSetSpec( stc.STC_STYLE_BRACEBAD  , "fore:#FFFFFF,back:#FF0000, bold" )
			# normal html
			self.StyleSetSpec( stc.STC_H_DEFAULT, "size:%s,face:%s,fore:%s" % ( common.default_font_size, common.default_font_family, common.sui_colors("darkslategray") ) )
			self.StyleSetSpec( stc.STC_H_TAG, "fore:#4433CC,bold" )
			self.StyleSetSpec( stc.STC_H_TAGUNKNOWN, "fore:#CC4455,back:%s,bold" % common.sui_colors("cornsilk") )
			self.StyleSetSpec( stc.STC_H_ATTRIBUTE, "fore:#336655" ) # #336655
			self.StyleSetSpec( stc.STC_H_ATTRIBUTEUNKNOWN, "fore:%s,back:%s" % ( common.sui_colors("indianred"), common.sui_colors("cornsilk") ) ) #fore:#555588
			self.StyleSetSpec( stc.STC_H_DOUBLESTRING, "fore:#888822" )
			self.StyleSetSpec( stc.STC_H_NUMBER, "fore:#992299" )
			self.StyleSetSpec( stc.STC_H_COMMENT, "fore:#11AA33,back:#EEFFEE" )
			# javascript
			self.StyleSetSpec( stc.STC_HJ_START, "bold,fore:%s,back:#ffefef,eol" )
			self.StyleSetSpec( stc.STC_HJ_DEFAULT, "size:%s,face:%s,back:#ffefef,fore:%s,eol" % ( common.default_font_size, common.default_font_family, common.sui_colors("mediumslateblue") ) )
			self.StyleSetSpec( stc.STC_HJ_SYMBOLS, "back:#ffefef,fore:%s,bold" % common.sui_colors("indianred") )
			self.StyleSetSpec( stc.STC_HJ_WORD, "back:#ffefef,fore:#4433CC,bold" )
			self.StyleSetSpec( stc.STC_HJ_REGEX, "fore:#CC0055,back:%s,bold" % common.sui_colors("cornsilk") )
			self.StyleSetSpec( stc.STC_HJ_SINGLESTRING, "back:#ffefef,fore:#336655" ) # #336655
			self.StyleSetSpec( stc.STC_HJ_KEYWORD, "fore:%s,back:%s,bold" % ( common.sui_colors("indianred"), common.sui_colors("cornsilk") ) ) #fore:#555588
			self.StyleSetSpec( stc.STC_HJ_DOUBLESTRING, "back:#ffefef,fore:#888822" )
			self.StyleSetSpec( stc.STC_HJ_NUMBER, "back:#ffefef,fore:#992299" )
			self.StyleSetSpec( stc.STC_HJ_COMMENT, "fore:#11aa44,back:#ffefef,eol" )
			self.StyleSetSpec( stc.STC_HJ_COMMENTLINE, "fore:#11aa44,back:#ffefef,eol" )
			self.StyleSetSpec( stc.STC_HJ_COMMENTDOC, "fore:#11aa44,back:#ffefef,eol" )
			# php		
			self.StyleSetSpec( stc.STC_HPHP_DEFAULT, "size:%s,face:%s,fore:#007F00" % ( common.default_font_size, common.default_font_family ) )
			self.StyleSetSpec( stc.STC_HPHP_HSTRING, "fore:yellow4" )
			self.StyleSetSpec( stc.STC_HPHP_SIMPLESTRING, "fore:#720072,back:lightyellow" )
			self.StyleSetSpec( stc.STC_HPHP_WORD, "bold,fore:#000072" )
			self.StyleSetSpec( stc.STC_HPHP_NUMBER, "bold,fore:#007F7F" )
			self.StyleSetSpec( stc.STC_HPHP_VARIABLE, "bold,fore:#0000FF" )
			self.StyleSetSpec( stc.STC_HPHP_COMMENT, "fore:#7F7F7F,back:mintcream" )
			self.StyleSetSpec( stc.STC_HPHP_COMMENTLINE, "fore:#008F00,back:azure" )
			self.StyleSetSpec( stc.STC_HPHP_HSTRING_VARIABLE, "fore:sienna4" )
			self.StyleSetSpec( stc.STC_HPHP_OPERATOR, "bold,fore:indianred4" )
			# keywords
			style_keywords = "%s%s%s" % ( html_keywords, html_attribs, css_keywords )
			self.SetKeyWords( 0, style_keywords )
			self.SetKeyWords( 4, php_keywords )
		
	def assign_keys( self ):
		# Dvorak Key movement
		self.CmdKeyAssign( 	ord( 'H' ),
							stc.STC_SCMOD_ALT,
							stc.STC_CMD_CHARLEFT )
		self.CmdKeyAssign( 	ord( 'N' ),
							stc.STC_SCMOD_ALT,
							stc.STC_CMD_CHARRIGHT )
		self.CmdKeyAssign( 	ord( 'C' ),
							stc.STC_SCMOD_ALT,
							stc.STC_CMD_LINEUP )
		self.CmdKeyAssign( 	ord( 'T' ),
							stc.STC_SCMOD_ALT,
							stc.STC_CMD_LINEDOWN )
		self.CmdKeyAssign( 	ord( 'D' ),
							stc.STC_SCMOD_ALT,
							stc.STC_CMD_WORDLEFT )
		self.CmdKeyAssign( 	ord( 'S' ),
							stc.STC_SCMOD_ALT,
							stc.STC_CMD_WORDRIGHT )
		self.CmdKeyAssign( 	ord( '-' ),
							stc.STC_SCMOD_ALT,
							stc.STC_CMD_LINEEND )
		self.CmdKeyAssign( 	ord( 'I' ),
							stc.STC_SCMOD_ALT,
							stc.STC_CMD_VCHOME )
		self.CmdKeyAssign( 	ord( 'G' ),
							stc.STC_SCMOD_ALT,
							stc.STC_CMD_PAGEUP )
		self.CmdKeyAssign( 	ord( 'M' ),
							stc.STC_SCMOD_ALT,
							stc.STC_CMD_PAGEDOWN )

		# Selection
		self.CmdKeyAssign(	ord( 'H' ),
							stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT,
							stc.STC_CMD_CHARLEFTEXTEND )
		self.CmdKeyAssign(	ord( 'N' ),
							stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT,
							stc.STC_CMD_CHARRIGHTEXTEND )
		self.CmdKeyAssign(	ord( 'C' ),
							stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT,
							stc.STC_CMD_LINEUPEXTEND )
		self.CmdKeyAssign(	ord( 'T' ),
							stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT,
							stc.STC_CMD_LINEDOWNEXTEND )
		self.CmdKeyAssign( ord( 'D' ),
							stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT,
							stc.STC_CMD_WORDLEFTEXTEND )
		self.CmdKeyAssign( ord( 'S' ),
							stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT,
							stc.STC_CMD_WORDRIGHTEXTEND )
		self.CmdKeyAssign( ord( '-' ),
							stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT,
							stc.STC_CMD_LINEENDEXTEND )
		self.CmdKeyAssign( ord( 'I' ),
							stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT,
							stc.STC_CMD_VCHOMEEXTEND )
		self.CmdKeyAssign( ord( 'G' ),
							stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT,
							stc.STC_CMD_PAGEUPEXTEND )
		self.CmdKeyAssign( ord( 'M' ),
							stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT,
							stc.STC_CMD_PAGEDOWNEXTEND )
		# Zooming
		self.CmdKeyAssign( ord( '=' ),
							stc.STC_SCMOD_CTRL | stc.STC_SCMOD_SHIFT,
							stc.STC_CMD_ZOOMIN )
		self.CmdKeyAssign( ord( '-' ),
							stc.STC_SCMOD_CTRL,
							stc.STC_CMD_ZOOMOUT )

	def set_value( self, text ):
		#print "The type of text is ",type( text )
		#text = common.uni2str( text )
		#common.dprint("Converted IN tabs \n%s" % text.replace("\t","******TAB******") )
		rw = self.GetReadOnly()
		self.SetReadOnly( False )
		self.SetText( text )
		self.SetReadOnly( rw )
		self.EmptyUndoBuffer()

	def get_value( self ):
		text = self.GetText()
		#common.dprint("Converted OUT tabs \n%s" % text.replace("\t","******TAB******") )
		return self.GetText()

	def set_readwrite( self, rw ):
		#print "rw:", rw
		self.SetReadOnly( not rw )

	def FreeUp( self ):
		self.undo_mi.Destroy()
		self.redo_mi.Destroy()
		self.cut_mi.Destroy()
		self.copy_mi.Destroy()
		self.paste_mi.Destroy()
		self.select_all_mi.Destroy()
		self.find_mi.Destroy()
		self.wrap_mi.Destroy()
		del self.undo_mi
		del self.redo_mi
		del self.cut_mi
		del self.copy_mi
		del self.paste_mi
		del self.select_all_mi
		del self.find_mi
		del self.wrap_mi
		del self.context_menu
		#self.DestroyChildren()
		self.Destroy()

	def OnMouseRightUp( self, event ):
		# Update the menu items
		self.undo_mi.Enable( self.CanUndo() )
		self.redo_mi.Enable( self.CanRedo() )
		#self.paste_mi.Enable( self.CanPaste() )
		wx.Yield()
		# Popup the menu
		self.PopupMenu( self.context_menu, wx.Point( event.m_x, event.m_y ) )

	def CreateContextMenu( self ):
		self.context_menu = wx.Menu()
		self.menu_start_id = 5000
		currentId = self.menu_start_id
		self.undo_mi = wx.MenuItem( self.context_menu, currentId, "Undo\tCtrl-Z", "" )
		currentId = currentId + 1
		self.context_menu.AppendItem( self.undo_mi )
		self.redo_mi = wx.MenuItem( self.context_menu, currentId, "Redo\tCtrl-Y", "" )
		currentId = currentId + 1
		self.context_menu.AppendItem( self.redo_mi )
		self.context_menu.AppendSeparator()
		self.cut_mi  = wx.MenuItem( self.context_menu, currentId, "Cut\tCtrl-X", "" )
		currentId = currentId + 1
		self.context_menu.AppendItem( self.cut_mi )
		self.copy_mi = wx.MenuItem( self.context_menu, currentId, "Copy\tCtrl-C", "" )
		currentId = currentId + 1
		self.context_menu.AppendItem( self.copy_mi )
		self.paste_mi= wx.MenuItem( self.context_menu, currentId, "Paste\tCtrl-V", "" )
		currentId = currentId + 1
		self.context_menu.AppendItem( self.paste_mi )
		self.context_menu.AppendSeparator()
		self.select_all_mi= wx.MenuItem( self.context_menu, currentId, "Select All", "" )
		currentId = currentId + 1
		self.context_menu.AppendItem( self.select_all_mi )
		self.context_menu.AppendSeparator()
		self.find_mi= wx.MenuItem( self.context_menu, currentId, "Find Text\tCtrl+F", "" )
		currentId = currentId + 1
		self.context_menu.AppendItem( self.find_mi )
		self.context_menu.AppendSeparator()
		self.wrap_mi= wx.MenuItem( self.context_menu, currentId, "Wrap Text\tCtrl+W", "", 1 )
		currentId = currentId + 1
		self.context_menu.AppendItem( self.wrap_mi )
		self.zoomin_mi= wx.MenuItem( self.context_menu, currentId, "Zoom In\tCtrl++", "" )
		currentId = currentId + 1
		self.context_menu.AppendItem( self.zoomin_mi )
		self.zoomout_mi= wx.MenuItem( self.context_menu, currentId, "Zoom Out\tCtrl+-", "" )
		currentId = currentId + 1
		self.context_menu.AppendItem( self.zoomout_mi )
		self.context_menu.AppendSeparator()
		self.script_mi= wx.MenuItem( self.context_menu, currentId, "Insert Script", "" )
		currentId = currentId + 1
		self.context_menu.AppendItem( self.script_mi )
		self.Bind( wx.EVT_MENU_RANGE, self.OnContextMenuAction, id=self.menu_start_id, id2=currentId )

	def OnContextMenuAction( self, event ):
		wx.Yield()
		aid = event.GetId()
		if aid == ( self.menu_start_id ):
			self.Undo()
		elif aid == ( self.menu_start_id + 1 ):
			self.Redo()
		elif aid == ( self.menu_start_id + 2 ):
			self.Cut()
		elif aid == ( self.menu_start_id + 3 ):
			self.Copy()
		elif aid == ( self.menu_start_id + 4 ):
			try: self.Paste()
			except: pass
		elif aid == ( self.menu_start_id + 5 ):
			self.SelectAll()
		elif aid == ( self.menu_start_id + 6 ):
			self.OnShowFindReplace()
		elif aid == ( self.menu_start_id + 7 ):
			if not self.wrap_text:
				self.SetWrapMode( stc.STC_WRAP_WORD )
				self.wrap_text = True
			else:
				self.SetWrapMode( stc.STC_WRAP_NONE )
				self.wrap_text = False
			self.wrap_mi.Check( self.wrap_text )
		elif aid == ( self.menu_start_id + 8 ):
			self.OnZoom( True )
		elif aid == ( self.menu_start_id + 9 ):
			self.OnZoom( False )
		elif aid == ( self.menu_start_id + 10 ):
			self.ShowScriptHelper()
			#dlg = script_helper.dialog( self )
			#res = dlg.ShowModal()
			#if res == wx.ID_OK:
				#script = dlg.code.GetText()
				#self.InsertText( self.GetCurrentPos(), script )
			#dlg.Destroy()
			
	def ShowScriptHelper( self ) :
		dlg = script_helper.dialog( self )
		res = dlg.ShowModal()
		if res == wx.ID_OK:
			script = dlg.code.GetText()
			self.InsertText( self.GetCurrentPos(), script )
		dlg.Destroy()

	def OnZoom( self, zoomin ):
		zoom = self.GetZoom()
		if zoomin:
			zoom = zoom + 1
		else:
			zoom = zoom - 1
		if zoom > 20: zoom = 20
		if zoom < -10: zoom = -10
		self.SetZoom( zoom )

	def OnShowMoreScripting( self, event ):
		webbrowser.open("http://www.etelos.com/esdnet/support/webformadvanced")

	def OnKeyUp( self, event ):
		key		= event.KeyCode
		if key == 13:		# Return
			# auto indent
			cline = self.GetCurrentLine()
			# Get the previous line indentation
			isize = self.GetLineIndentation( cline - 1 )
			if isize < 1: return
			self.SetLineIndentation( cline, isize )
			# Move the current position to the end of this new line
			cpos = self.GetLineIndentPosition( cline )
			self.SetSelectionStart( cpos )
			self.SetSelectionEnd( cpos )

	def OnChanged( self, event ):
		#print "editor sui", self.sui, self.GetModify()
		if( self.GetModify() ):
			common.dprint(" editor var_id ", self.var_id )
			common.dprint("setting dirty on class ", self.editor )
			if self.editor.__class__ == questions_editor:
				common.dprint("setting dirty on class's parent ", self.editor.parent )
				self.editor.parent.set_var_dirty( self.var_id )
			elif self.editor.__class__ == sui_question_props:
				common.dprint("setting dirty on class's parent's parent ", self.editor.GetParent().GetParent().GetParent().parent )
				self.editor.GetParent().GetParent().GetParent().parent.set_var_dirty( self.var_id )
			else:	
				self.editor.set_var_dirty( self.var_id )

	def OnDragOver( self, event ):
		event.SetDragResult( wx.DragCopy )
		return wx.DragCopy

	#~ def OnDoDrop( self, event ):
		#~ print "On DROP"
		#~ dir( event )
		#~ self.Undo()
		#~ return 0


	def OnKeyPressed( self, event ):
		common.dprint(event)
		if self.CallTipActive():
			self.CallTipCancel()
		key = event.KeyCode
		handled = False
		# CTRL
		#print "Control:", event.ControlDown()
		#print "Alt:", event.AltDown()
		#print "Meta:", event.MetaDown()
		control_down = event.ControlDown()
		if wx.Platform == '__WXMAC__': 
			control_down = event.MetaDown()
		if control_down:
			# Space
			if key == 32:
				handled = True
				pos = self.GetCurrentPos()
				# Tips
				if event.ShiftDown():
					self.CallTipSetBackground("yellow")
					self.CallTipShow(pos, 'param1, param2')
				# Code completion
				else:
					kw = keywords.kw_all_string
					self.AutoCompSetIgnoreCase(False)  # so this needs to match
					self.AutoCompShow( 0, kw )
			# Find
			elif key == ord('F'):
				handled = True
				self.OnShowFindReplace()
			# Undo
			elif key == ord('Z'):
				handled = True
				self.Undo()
			# Save
			elif key == ord('S'):
				handled = True
				if self.editor: self.editor.OnSave( None )
			elif key == ord('Y'):
				handled = True
				self.Redo()
			elif key == ord('W'):
				handled = True
				if not self.wrap_text:
					self.SetWrapMode( stc.STC_WRAP_WORD )
					self.wrap_text = True
				else:
					self.SetWrapMode( stc.STC_WRAP_NONE )
					self.wrap_text = False
				self.wrap_mi.Check( self.wrap_text )
			# Toggle HTML/TEXT
			elif key == ord('T'):
				handled = True
				if self.editor:
					self.editor.toggle_texthtml()
			# next variable
			elif key == ord('`'):
				handled = True
				if self.editor:
					if event.ShiftDown():
						self.editor.select_prev_variable()
					else:
						self.editor.select_next_variable()
			elif ( key == ord('1') ) or ( key == ord('2') ) or ( key == ord('3') ) or ( key == ord('4') ):
				if self.editor: self.editor.account.window.OnKeyPressed( event )
		else:
			# No control key
			if key == wx.WXK_F3:
				if event.ShiftDown():
					self.OnShowFindReplace()
				else:
					self.OnShowFindReplace()
		# if we handled the key press, stop sending it up
		if not handled: 
			event.StopPropagation()
			event.Skip()

	def OnShowFindReplace( self ):
		#~ data = wx.FindReplaceData()
		#~ dlg = wx.FindReplaceDialog(self, data, "Find & Replace", wx.FR_REPLACEDIALOG)
		#~ dlg.data = data  # save a reference to it...
		#~ dlg.Show(True)
		self.editor.show_findbar()

	def OnFindReplace( self, operation, start=None, end=None ):
		if common.finddata['case']:
			self.SetSearchFlags( stc.STC_FIND_MATCHCASE )
		else:
			self.SetSearchFlags( 0 )
		#print "%s -- Find text: %s  %s  Flags: %d  \n" % (evtType, evt.GetFindString(), replaceTxt, evt.GetFlags())
		# Find, Replace
		if operation == 'find':
			#common.dprint("Finding")
			for_replace = False
			if start and end:
				self.SetTargetStart( start )
				self.SetTargetEnd  ( end )
				for_replace = True
			elif common.finddata['forward']:
				self.SetTargetStart( self.GetSelectionEnd() )
				self.SetTargetEnd  ( self.GetLength() )
			else:
				self.SetTargetStart( self.GetSelectionStart() - 1 )
				self.SetTargetEnd  ( 0 )
			pos = self.SearchInTarget( common.finddata['text'] )
			if pos > 0:
				#common.dprint( "Found" )
				end = pos + len( common.finddata['text'] )
				# select the found text unless we got instructions from a replace operation
				if not for_replace: self.SetSelection( pos, end )
				return pos
			else:
				#common.dprint( "Not Found, looping" )
				# Try one more time, loop
				if common.finddata['forward']:
					self.SetTargetStart( 0 )
					self.SetTargetEnd  ( self.GetLength() )
				else:
					self.SetTargetStart( self.GetLength() - 1 )
					self.SetTargetEnd  ( 0 )
				pos = self.SearchInTarget( common.finddata['text'] )
				if pos > 0:
					#common.dprint( "Found" )
					end = pos + len( common.finddata['text'] )
					# select the found text unless we got instructions from a replace operation
					if not for_replace: self.SetSelection( pos, end )
					return pos
				else:
					#common.dprint( "Not Found, for real" )
					return -1
		# Replace All
		elif operation == 'replace':
			if common.finddata['all']:
				start = 0
				end = self.GetLength() - 1
			else:
				start = self.GetSelectionStart()
				end = self.GetSelectionEnd()
			original_start = start
			original_end = end
			positions = []
			length_diff = len( common.finddata['rtext'] ) - len( common.finddata['text'] )
			#common.dprint( "length diff ", length_diff )
			pos = self.OnFindReplace( 'find', start, end )
			# Outside the selection?
			if not common.finddata['all'] and ( pos > end or pos < start ): return True
			while pos >= 0:
				positions.append( pos )
				#common.dprint( "Found, replacing at ", pos )
				self.ReplaceTarget( common.finddata['rtext'] )
				start = pos + len( common.finddata['rtext'] )
				if not common.finddata['all']: original_end = end = end + length_diff
				pos = self.OnFindReplace( 'find', start, end )
				#common.dprint( "Found next one at ", pos, "end ", end )
				if pos in positions: break
				# Outside the selection?
				if not common.finddata['all'] and ( pos > end or pos < start ): break
			if not common.finddata['all']: self.SetSelection( original_start, original_end )
		return True

	###########################
	def OnFindClose(self, evt):
		evt.GetDialog().Destroy()

class text_drop_target( wx.PyDropTarget ):
	def __init__( self, editor, action, for_what ):
		wx.PyDropTarget.__init__( self )
		self.action = action
		self.editor = editor
		self.defaultCaretPeriod = editor.GetCaretPeriod()
		self.for_what=for_what
		self.data   = wx.PyTextDataObject(" ")
		self.SetDataObject( self.data )

	def OnEnter( self, x, y, d ):
		#print "SubLock data:", d
		return wx.DragCopy

	def OnLeave( self ):
		pass

	def OnDrop( self, x, y ):
		return True

	def OnDragOver( self, x, y, d ):
		pos = self.editor.PositionFromPoint( wx.Point(x,y) )
		self.editor.GotoPos( pos )
		#self.editor.SetCurrentPos( pos )
		self.editor.SetSTCFocus( True )
		self.editor.SetCaretPeriod( 0 )
		#common.dprint( "going to position ", pos )
		return wx.DragCopy

	def OnData( self, x, y, d ):
		pos = self.editor.PositionFromPoint( wx.Point(x,y) )
		common.dprint( "x:", x, "  y:", y, "  pos:", pos )
		self.editor.SetCaretPeriod( self.defaultCaretPeriod )
		try :
			if self.GetData():
				data = self.data.GetText()
				common.dprint( "Data Dropped", data )
				#if( data[3:9] == "BINDER" ) :
				binfinder = re.compile( '([_a-zA-Z0-9\s]+)\.([0-9]+)' )
				insfinder = re.compile( '([0-9]+)\.([0-9]+)\|([_a-zA-Z0-9\s]+)\.([_a-zA-Z0-9\s]+)' )
				pubfinder = re.compile( '<publication[_=\"\'a-zA-Z0-9\s]+id=\"([0-9]+)\"' )
				bin = binfinder.match( data )
				ins = insfinder.match( data )
				pub = pubfinder.match( data )
				if bin and not ins and not pub :
					common.dprint( "Dropping binder" )
					subdata = { "bid":bin.group( 2 ) }
					subdata = self.getBinderProperties( subdata["bid"], bin.group( 1 ) )
					subdata["tag"] = "<#[BINDER_"+subdata["bid"]+"]#>"
					choices = ['Simple Binder Instance List', 'Simple Binder Form', 'Binder Tag']
					dlg = wx.SingleChoiceDialog(self.editor, 'Insert Binder', 'Insert binder as:', choices, wx.CHOICEDLG_STYLE)
					common.metalic( dlg )
					if dlg.ShowModal() == wx.ID_OK:
						choice = dlg.GetStringSelection()
					dlg.Destroy()
					sil = re.compile( "BINDER_ID" )
					sif = re.compile( "bid.instance_id" )
					choice = {
						#'Simple Binder Instance List': lambda data: sil.sub( id, SIMPLE_INSTANCE_LIST ),
						'Simple Binder Instance List': lambda subdata: self.buildBinderList( subdata ),
						#'Simple Binder Form': lambda data: sif.sub( id + ".instance_id", SIMPLE_INSTANCE_FORM ),
						'Simple Binder Form': lambda subdata: self.buildBinderForm( subdata ),
						'Binder Tag': lambda subdata: subdata["tag"]
					}[choice](subdata)
					self.editor.InsertTextRaw( pos, str( choice ) )
				elif ins and not pub :
					common.dprint( "Dropping instance" )
					bid = ins.group( 1 )
					iid = ins.group( 2 )
					bname = ins.group( 3 )
					iname = ins.group( 4 )
					common.dprint( "Found instance named", iname, "with id", iid, "as part of binder", bid )
					subdata = self.getInstanceProperties( bid, bname, iid, iname )
					subdata["tag"] = "<#[INSTANCE_"+bid+"_"+iid+"]#>"
					choices = ['Simple Instance Form', 'Instance Tag']
					dlg = wx.SingleChoiceDialog(self.editor, 'Insert Instance', 'Insert instance as:', choices, wx.CHOICEDLG_STYLE)
					choice = ""
					if dlg.ShowModal() == wx.ID_OK:
						choice = dlg.GetStringSelection()
					dlg.Destroy()
					#sif = re.compile( "bid.instance_id" )
					choice = {
						'Simple Instance Form': lambda subdata: self.buildBinderForm( subdata, iid ),
						'Instance Tag': lambda subdata: subdata["tag"]
					}[choice](subdata)
					self.editor.InsertTextRaw( pos, str( choice ) )
				else :
					if pub :
						pid = pub.group( 1 )
						common.dprint( "Dropping publication", pid )
						data = "<#[PUBLICATION_"+pid+"]#>"
					else :
						common.dprint( "Dropping something else", str(data) )
					self.editor.InsertTextRaw( pos, str(data) )
			else:
				common.dprint( "Failed to get the dnd data" )
		except:
			common.dprint( "Drag and Drop failed for data: ", str(data) )
		return wx.DragNone
	
	def buildBinderForm( self, data, specific_instance = 0 ):
		bnamesub = data["bname"]
		bidsub = data["bid"]
		vars = data["vars"]
		common.dprint("Generating a form for binder", data)
		bid = re.compile( "__bid__" )
		iid = re.compile( "__iid__" )
		bname = re.compile( "__bname__" )
		iname = re.compile( "__iname__" )
		vname = re.compile( "__vname__" )
		returndata = ""
		if bnamesub == u'CONTACT':
			returndata = bname.sub( 'contact', SIMPLE_CONTACT_FORM_HEAD )
			ignore = ['uuid','id','xid','created_on','html']
			for var in vars :
				vnamesub = var["name"].lower()
				if vnamesub in ignore: continue
				returndata += vname.sub( vnamesub.title(), SIMPLE_CONTACT_FORM_VAR_TEMPLATE )
			returndata += SIMPLE_CONTACT_FORM_FOOT
		else:
			if specific_instance :
				returndata = iname.sub( data["iname"], bname.sub( bnamesub, iid.sub( data["iid"], bid.sub( bidsub, SIMPLE_INSTANCE_FORM_HEAD ) ) ) )
			else:
				returndata = iname.sub( "instance_name", bname.sub( bnamesub, iid.sub( "!#[url_string.edit]#!", bid.sub( bidsub, SIMPLE_INSTANCE_FORM_HEAD ) ) ) )
			ignore = ['instance_id', 'instance_name', 'created_on']
			for var in vars :
				vnamesub = var["name"].lower()
				if vnamesub in ignore : continue
				returndata += vname.sub( vnamesub.title(), SIMPLE_INSTANCE_FORM_VAR_TEMPLATE )
			returndata += SIMPLE_INSTANCE_FORM_FOOT
		return returndata
	
	def buildBinderList( self, data ):
		bnamesub = data["bname"]
		bidsub = data["bid"]
		vars = data["vars"]
		bid = re.compile( "__bid__" )
		bname = re.compile( "__bname__" )
		vname = re.compile( "__vname__" )
		returndata = ""
		if bnamesub == u'CONTACT':
			returndata += bid.sub( bnamesub, SIMPLE_CONTACT_LIST_HEAD )
			returndata += SIMPLE_CONTACT_LIST_VAR_LIST_BEGIN
			# variables to ignore
			ignore = ['id', 'uuid']
			for var in vars:
				vnamesub = var["name"].lower()
				if vnamesub in ignore: continue
				returndata += vname.sub( vnamesub.title(), SIMPLE_CONTACT_LIST_VAR_LIST_ITEM )
			returndata += SIMPLE_CONTACT_LIST_VAR_LIST_END
			returndata += SIMPLE_CONTACT_LIST_BODY
			for var in vars:
				vnamesub = var["name"].lower()
				if vnamesub in ignore: continue
				returndata += vname.sub( vnamesub.title(), SIMPLE_CONTACT_LIST_BODY_VAR )
			returndata += SIMPLE_CONTACT_LIST_BODY_END
			for var in vars:
				vnamesub = var["name"]
				if vnamesub in ignore: continue
				returndata += vname.sub( vnamesub, SIMPLE_CONTACT_LIST_LIST_VAR )
			returndata += SIMPLE_CONTACT_LIST_FOOT
		else:
			returndata += bid.sub( bnamesub, SIMPLE_INSTANCE_LIST_HEAD )
			returndata += SIMPLE_INSTANCE_LIST_VAR_LIST_BEGIN
			# variables to ignore
			ignore = ['instance_id', 'instance_name']
			for var in vars:
				vnamesub = var["name"].lower()
				if vnamesub in ignore: continue
				returndata += vname.sub( vnamesub.title(), SIMPLE_INSTANCE_LIST_VAR_LIST_ITEM )
			returndata += SIMPLE_INSTANCE_LIST_VAR_LIST_END
			returndata += SIMPLE_INSTANCE_LIST_BODY
			for var in vars:
				vnamesub = var["name"].lower()
				if vnamesub in ignore: continue
				returndata += vname.sub( vnamesub.title(), SIMPLE_INSTANCE_LIST_BODY_VAR )
			returndata += SIMPLE_INSTANCE_LIST_BODY_END
			for var in vars:
				vnamesub = var["name"].lower()
				if vnamesub in ignore: continue
				returndata += vname.sub( vnamesub.title(), SIMPLE_INSTANCE_LIST_LIST_VAR )
			returndata += SIMPLE_INSTANCE_LIST_FOOT
		return returndata
	
	def buildBinderTag( self, data ):
		#something
		return
		
	def buildInstanceForm( self, data ): 
		return buildBinderForm( data, True )

	def buildInstanceTag( self, data ):
		#something
		return
	
	def getInstanceProperties( self, bid, bname, iid, iname ):
		returndata = self.getBinderProperties( bid, bname )
		returndata["iid"] = iid
		returndata["iname"] = iname
		return returndata
		
	def getBinderProperties( self, bid, bname ):
		bin = self.getBinderFromUI( bid, bname )
		returnarray = { "bid":bid }
		returnarray["vars"] = bin.variables
		returnarray["bname"] = bin["name"]
		return returnarray
	
	def getBinderFromUI( self, bid, bname ) :
		try: 
			binderslist = self.editor.editor.account.window.binder_control.binders
			for binder in binderslist :
				if binder["id"] == bid and binder["name"] == bname:
					return binder
		except:
			pass
			
	def getInstanceFromUI( self, bid, bname, iid ) :
		try:
			bin = self.getBinderFromUI( bid, bname )
			instancelist = bin.instances
			for instance in instancelist :
				if instance["id"] == iid:
					return instance
		except:
			pass
		
class texthtml( text ):
	"""Takes care of editing two variables with one interface"""
	def __init__( self, editor ):
		self.html = True
		text.__init__( self, editor )

	def set_value( self, text ):
		#print "The type of text is ",type( text )
		self.html = self.editor.get_texthtml()
		if self.html:
			#print "setting  the HTML version"
			# set the html version
			text = text[1]
		else:
			#print "setting  the TEXT version"
			# set the text version
			text = text[0]
		#print text
		#text = common.uni2str( text )
		rw = self.GetReadOnly()
		self.SetReadOnly( False )
		self.SetText( text )
		self.SetReadOnly( rw )
		self.EmptyUndoBuffer()
		

class choice( wx.Panel ):
	def __init__( self, editor ):
		wx.Panel.__init__( self, editor.vSplitter, -1 )
		# The top level sui object if any
		self.editor = editor
		self.options= []
		self.map 	= {}
		# the current variable being edited
		self.var_id = None
		sizer = wx.BoxSizer( wx.HORIZONTAL )
		self.cb = wx.Choice( self, -1 )
		sizer.Add( self.cb, 1, wx.ALL, 20 )
		self.Bind( wx.EVT_CHOICE, self.OnChoice )
		self.SetSizer( sizer )
		self.SetAutoLayout( 1 )
		self.Layout()
		self.Show()

	def OnChoice( self, event ):
		#print "Choice changed"
		self.editor.set_var_dirty( self.var_id )

	def set_options( self, options ):
		self.cb.Clear()
		self.options= []
		self.map	= {}
		for option in options:
			self.map[ option[0] ] = self.cb.Append( option[1] )
			self.options.append( option[0] )
		#print "Options", self.map

	def set_value( self, value ):
		#print "set choice to ",  value
		index = 0
		try:
			index = self.map[ value ]
		except:
			pass
		self.cb.SetSelection( index )

	def get_value( self ):
		index = self.cb.GetSelection()
		value = self.options[ index ]
		#print "returning value", value
		return value

	def set_readwrite( self, rw ):
		#print "setting readwrite", rw
		self.cb.Enable( rw )

class number( wx.Panel ):
	def __init__( self, editor ):
		wx.Panel.__init__( self, editor.vSplitter, -1 )
		# The top level sui object if any
		self.editor = editor
		# the current variable being edited
		self.var_id = None
		sizer = wx.BoxSizer( wx.HORIZONTAL )
		self.cb = wx.SpinCtrl( self, -1 )
		self.cb.SetRange( 0, 9999 )
		sizer.Add( self.cb, 0, wx.ALL, 20 )
		self.Bind( wx.EVT_SPINCTRL, self.OnSpin )
		self.SetSizer( sizer )
		self.SetAutoLayout( 1 )
		self.Layout()
		self.Show()

	def OnSpin( self, event ):
		#print "Spin changed"
		self.editor.set_var_dirty( self.var_id )

	def set_value( self, value ):
		#print "set choice to ",  value
		try:
			self.cb.SetValue( int( value ) )
		except:
			common.show_error( "Failed to set value [%s] into number editor" % ( str( value ) ), False )

	def get_value( self ):
		value = 0
		try:
			value = int( self.cb.GetValue() )
		except:
			common.show_error("You must enter a number")
		return value

	def set_readwrite( self, rw ):
		#print "setting readwrite", rw
		self.cb.Enable( rw )


class date( wx.Panel ):
	def __init__( self, editor ):
		wx.Panel.__init__( self, editor.vSplitter, -1 )
		# The top level sui object if any
		self.editor = editor
		self.var_id = None
		sizer = wx.BoxSizer( wx.HORIZONTAL )
		self.cb = wx.calendar.CalendarCtrl( self, -1, wx.DateTime_Now() )
		sizer.Add( self.cb, 0, wx.ALL, 20 )
		self.Bind( wx.calendar.EVT_CALENDAR_SEL_CHANGED, self.OnDateChanged, id=self.cb.GetId() )
		self.SetSizer( sizer )
		self.SetAutoLayout( 1 )
		self.Layout()

		# the current variable being edited
		self.Show()

	def OnDateChanged( self, event ):
		self.editor.set_var_dirty( self.var_id )

	def set_value( self, value ):
		#print "set choice to ",  value
		d = wx.DateTime_Now()
		if value.strip() != '' or value.find("1899") >= 0:
			# we have a value, lets try to parse
			try:
				d.ParseDate( value )
			except:
				common.show_error("Invalid date value [%s]" % value )
				d = wx.DateTime_Now()
		#print date
		self.cb.SetDate( d )

	def get_value( self ):
		value = 0
		#print "date get value"
		try:
			d = self.cb.GetDate()
			value = "%s-%s-%s" % ( d.GetYear(), d.GetMonth() + 1, d.GetDay() )
		except:
			common.show_error("You must enter a number")
		#print "returnig get value", value
		return value

	def set_readwrite( self, rw ):
		self.cb.Enable( rw )

class frequency( wx.Panel ):
	'''Provides the UI to manipulate frequency properties'''
	def __init__( self, editor ):
		wx.Panel.__init__( self, editor.vSplitter, -1 )
		self.editor = editor
		self.var_id = None
		self.formula_choices = ["Days of the week", "Days of the month", "Months of the year" ]
		top_label 		= wx.StaticText( self, -1, "Publish this issue when:" )
		# Create the match fields
		self.match_panel= wx.Panel( self, -1 )
		sizer 			= wx.BoxSizer( wx.HORIZONTAL )
		self.match_panel.SetSizer( sizer )
		self.match_panel.SetAutoLayout( 1 )
		self.matchla 	= wx.CheckBox( self, -1, "The Recurrence Variable matches the current date's" )
		#.Bind( wx.EVT_RADIOBUTTON( self, self.matchla.GetId(), self.on_use_match )
		self.matchla.Bind( wx.EVT_CHECKBOX, self.on_use_match )
		self.match_day 	= wx.CheckBox( self.match_panel, -1, "Day"  )
		self.match_day.Bind( wx.EVT_CHECKBOX, self.on_change )
		self.match_month= wx.CheckBox( self.match_panel, -1, "Month")
		self.match_month.Bind( wx.EVT_CHECKBOX, self.on_change )
		self.match_year	= wx.CheckBox( self.match_panel, -1, "Year" )
		self.match_year.Bind( wx.EVT_CHECKBOX, self.on_change )
		sizer.Add( self.match_day, 	1, wx.EXPAND | wx.ALIGN_CENTER )
		sizer.Add( self.match_month,1, wx.EXPAND | wx.ALIGN_CENTER )
		sizer.Add( self.match_year, 1, wx.EXPAND | wx.ALIGN_CENTER )
		# Create the formula fields
		self.formu_panel= wx.Panel( self, -1 )
		sizer 			= wx.BoxSizer( wx.VERTICAL )
		fsizer 			= wx.BoxSizer( wx.HORIZONTAL )
		self.formu_panel.SetSizer( sizer )
		self.formu_panel.SetAutoLayout( 1 )
		self.formula 	= wx.CheckBox( self, -1, "The current date matches the formula" )
		self.formula.Bind( wx.EVT_CHECKBOX, self.on_use_formula )
		self.formu_combo= wx.Choice( self.formu_panel, -1, choices=self.formula_choices )
		self.formu_combo.Bind( wx.EVT_CHOICE, self.on_formula_changed )
		self.formu_combo.SetSelection( 0 )
		self.formu_value= wx.TextCtrl( self.formu_panel, -1 )
		self.formu_value.Bind( wx.EVT_TEXT, self.on_change )
		self.formu_desc = wx.StaticText( self.formu_panel, -1, "El Descripcion" )
		fsizer.Add( self.formu_combo, 0, wx.EXPAND )
		fsizer.Add( self.formu_value, 1, wx.EXPAND )
		sizer.Add ( fsizer, 0, wx.EXPAND )
		sizer.Add ( self.formu_desc, 1, wx.EXPAND )

		self.sizer = wx.BoxSizer( wx.VERTICAL )
		self.sizer.Add( top_label, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.NORTH | wx.EAST | wx.WEST, 5 )
		self.sizer.Add( self.matchla, 0, wx.EXPAND | wx.ALIGN_CENTER  | wx.NORTH | wx.EAST | wx.WEST, 10 )
		self.sizer.Add( self.match_panel, 1, wx.EXPAND  | wx.SOUTH | wx.WEST, 20 )
		self.sizer.Add( self.formula, 0, wx.EXPAND | wx.ALIGN_CENTER  | wx.NORTH | wx.SOUTH | wx.EAST | wx.WEST, 10 )
		self.sizer.Add( self.formu_panel, 1, wx.EXPAND  | wx.SOUTH | wx.WEST, 20 )
		#
		self.SetSizer( self.sizer )
		self.SetAutoLayout( 1 )
		# Windows needs this call
		self.match_panel.Layout()
		self.formu_panel.Layout()
		self.Layout()
		#self.SetValue( value )

	def set_value( self, value ):
		value = value.strip()
		if len( value ) < 1:
			# Select the defaults
			self.on_use_match( None )
			return
		# Try to get a match match
		pat = re.compile("Date[ ]+match[ ]+recurrence[ ]+variable[ ]+on[ ]*\((.*)\)", re.I )
		m 	= pat.match( value )
		if m:
			self.on_use_match( None )
			token = m.groups()[0]
			#print "Token: ", token
			if token.upper().find("DAY") >= 0:
				self.match_day.SetValue( 1 )
			else:
				self.match_day.SetValue( 0 )

			if token.upper().find("MONTH") >= 0:
				self.match_month.SetValue( 1 )
			else:
				self.match_month.SetValue( 0 )

			if token.upper().find("YEAR") >= 0:
				self.match_year.SetValue( 1 )
			else:
				self.match_year.SetValue( 0 )
			return

		# Lets try a formula match
		possible  = "|".join( self.formula_choices )
		pat = re.compile("Date[ ]+match[ ]+on[ ]+(" + possible +")[ ]*\((.*)\)", re.I )
		m 	= pat.match( value )
		if m:
			self.on_use_formula( None )
			index = self.formula_choices.index( m.groups()[0] )
			self.formu_combo.SetSelection( index )
			self.formu_value.SetValue( m.groups()[1] )
			return

		# Otherwise, Select the defaults
		self.on_use_match( None )


	def get_value( self ):
		value = "Date match Recurrence Variable on "
		if self.matchla.GetValue():
			mpart = []
			if self.match_day.GetValue():	mpart.append("day")
			if self.match_month.GetValue():	mpart.append("month")
			if self.match_year.GetValue():	mpart.append("year")
			value = value + "(" + ",".join( mpart ) + ")"
		else:
			sel   = self.formu_combo.GetSelection()
			formu = self.formula_choices[ sel ]
			forval= self.formu_value.GetValue()
			value = "Date match on %s (%s)" % ( formu, forval )
		return value

	def set_readwrite( self, rw ):
		self.Enable( rw )
	#~ def OnOK( self, event ):
		#~ if self.matchla.GetValue():
			#~ if( self.match_day.GetValue() == 0 ) and \
			  #~ ( self.match_month.GetValue() == 0 ) and \
			  #~ ( self.match_day.GetValue() == 0 ):
				#~ self.match_day.SetValue( 0 )
				#~ dlg = wx.MessageDialog( None, "You must select to match by day, by month, and/or by year", "Missing Value",wx.OK )
				#~ icon = icon_manager.get_icon( "ESM" )
				#~ dlg.SetIcon( icon )
				#~ dlg.ShowModal()
				#~ return True
		#~ elif self.formula.GetValue():
			#~ frmval = self.formu_value.GetValue()
			#~ if len( frmval.strip() ) < 1:
				#~ sel   = self.formu_combo.GetSelection()
				#~ formu = self.formula_choices[ sel ]
				#~ dlg = wx.MessageDialog( None, "You enter the value for \"%s\"" % formu, "Missing Value", wx.OK )
				#~ icon = icon_manager.get_icon( "ESM" )
				#~ dlg.SetIcon( icon )
				#~ dlg.ShowModal()
				#~ return True
		#~ self.parent.set_property( True )
		#~ self.Destroy()

	def on_change( self, event ):
		self.editor.set_var_dirty( self.var_id )

	def on_use_match( self, event ):
		self.formu_panel.Enable( False )
		self.match_panel.Enable( True  )
		self.matchla.SetValue( 1 )
		self.formula.SetValue( 0 )
		self.on_formula_changed( None )
		self.editor.set_var_dirty( self.var_id )

	def on_use_formula( self, event ):
		self.formu_panel.Enable( True  )
		self.match_panel.Enable( False )
		self.matchla.SetValue( 0 )
		self.formula.SetValue( 1 )
		self.on_formula_changed( None )
		self.editor.set_var_dirty( self.var_id )

	def on_formula_changed( self, event ):
		sel = self.formu_combo.GetSelection()
		if sel == 0:
			desc = '''Examples:
Mon, Wed, Fri
M, W, F
1, 3
Tuesday'''
		elif sel == 1:
			desc = '''Examples:
1, 15, 28
10, 20
15'''
		elif sel == 2:
			desc = '''Examples:
Jan, Jun
1, 3, 6, 9
January, October, December '''
		else:
			return
		self.formu_desc.SetLabel( desc )
		self.editor.set_var_dirty( self.var_id )


class sb_drop_target( wx.PyDropTarget ):
	def __init__( self, editor, action, for_what ):
		wx.PyDropTarget.__init__( self )
		self.action = action
		self.editor = editor
		self.for_what=for_what
		self.data   = wx.PyTextDataObject(" ")
		self.SetDataObject( self.data )

	def OnEnter( self, x, y, d ):
		#print "SubLock data:", d
		return wx.DragCopy

	def OnLeave( self ):
		pass

	def OnDrop( self, x, y ):
		return True

	def OnDragOver( self, x, y, d ):
		return wx.DragCopy

	def OnData( self, x, y, d ):
		common.dprint( x, y, d )
		if self.GetData():
			data = self.data.GetText()
			common.dprint( "Data Dropped", data )
			if( data[:12]=="<publication" ) and ( self.for_what=="PUBLICATIONS" ):
				# We are subscribing the contact to a publication
				common.dprint('publication dropped')
				pub = rex.publications.publication( self.editor.editor.account, 'web', data )
				if isinstance( self.editor.editor.rex_object, rex.contacts.group ):
					cdom = "<instructions><instruction action=\"%s\" publication_id=\"%s\" group_id=\"%s\" /></instructions>" % \
					( self.action, pub["id"], self.editor.editor.rex_object["id"] )
				else:
					return wx.DragNone
				result = self.editor.editor.account.execute( 'base', "subscriptions_addremove", DOM=cdom )
				icon = self.editor.get_icon_from_rex_object( pub )
				x = self.editor.list.InsertImageStringItem( sys.maxint,  pub["id"], icon  )
				self.editor.list.SetStringItem( x , 1, pub["name"] )
				self.editor.resize_columns()
				return wx.DragCopy
			if( data[0]=="[" ) and ( data[-1]=="]" ) and ( self.for_what=="INSTANCES" ):
				# We are applying binder instances
				tag = data.replace("[","").replace("]","")
				id_tag = ''
				name_tag = ''
				try:
					id_tag,name_tag = tag.split('|')
				except:
					common.show_error("Failed to parse instance tag")
					return
				if isinstance( self.editor.editor.rex_object, rex.contacts.contact ):
					cdom = "<instructions><instruction action=\"%s\" contact_id=%s instance=%s /></instructions>" % \
					( self.action, saxutils.quoteattr( self.editor.editor.rex_object["id"] ), \
					  saxutils.quoteattr( id_tag ) )
				elif isinstance( self.editor.editor.rex_object, rex.contacts.group ):
					cdom = "<instructions><instruction action=\"%s\" group_id=\"%s\" instance=%s /></instructions>" % \
					( self.action, self.editor.editor.rex_object["id"], saxutils.quoteattr( id_tag ) )
				else:
					return wx.DragNone
				result = self.editor.editor.account.execute( 'base', "instances_addremove", DOM=cdom )
				x = self.editor.list.InsertImageStringItem( sys.maxint,  id_tag, self.editor.instance_icon  )
				self.editor.list.SetStringItem( x , 1, name_tag )
				item = self.editor.list.GetItem(x)
				if isinstance( self.editor.editor.rex_object, rex.contacts.contact ):
					self.editor.list.SetStringItem( x , 3, 'Applied Directly' )
					self.editor.list.SetItemBackgroundColour( x, common.sui_colors("whitesmoke") )
				self.editor.resize_columns()
				return wx.DragCopy
		else:
			common.dprint( "Failed to get the dnd data" )
		return wx.DragNone


class sub_block_base( wx.Panel ):
	def __init__( self, editor, action ):
		wx.Panel.__init__( self, editor.vSplitter, -1 )
		self.editor = editor
		self.var_id = None
		self.action = action
		# Add the subscriptions page
		sizer = wx.BoxSizer( wx.HORIZONTAL )
		self.list = wx.ListCtrl( self, style=wx.LC_REPORT )
		self.il = wx.ImageList( 16,16 )
		self.folder_w_icon = self.il.Add( images.getFolderWBitmap() )
		self.folder_n_icon = self.il.Add( images.getFolderNBitmap() )
		self.folder_e_icon = self.il.Add( images.getFolderEBitmap() )
		self.group_icon	   = self.il.Add( images.getGroupBitmap() )
		self.list.SetImageList( self.il, wx.IMAGE_LIST_SMALL )
		sizer.Add( self.list, 1, wx.EXPAND)
		info = wx.ListItem()
		info.m_mask = wx.LIST_MASK_TEXT # | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
		info.m_format = 0
		info.m_text = "ID"
		self.list.InsertColumnInfo(0, info)
		info.m_text = "Name"
		self.list.InsertColumnInfo(1, info)
		if isinstance( self.editor.rex_object, rex.contacts.contact ):
			info.m_text = "Group ID"
			self.list.InsertColumnInfo(2, info)
			info.m_text = "Group Name"
			self.list.InsertColumnInfo(3, info)
		# Set the drop target
		dt = sb_drop_target( self, self.action, "PUBLICATIONS" )
		self.list.SetDropTarget( dt )
		# Set the drag and drop events
		#if wx.Platform != '__WXMAC__':
		self.list.Bind( wx.EVT_LIST_BEGIN_DRAG, self.OnBeginDrag, id=self.list.GetId() )
		self.SetSizer( sizer )
		self.SetAutoLayout( 1 )
		self.Layout()
		#
		menu = wx.Menu()
		menu.Append( ID_PUB_PASTE, "&Subscribe", " Paste the publication from the clipboard" )
		menu.Append( ID_PUB_CUT, "&UnSubscribe", " Remove the selected publication" )
		self.pub_menu = menu
		self.Bind( wx.EVT_MENU, self.OnPublicationPaste, id=ID_PUB_PASTE )
		self.Bind( wx.EVT_MENU, self.OnPublicationCut, id=ID_PUB_CUT )
		self.list.Bind( wx.EVT_RIGHT_DOWN, self.OnPublicationListRightClick )

	def resize_columns( self ):
		'''Used internally to recalculate the column sizes'''
		# Set the column header sizes
		for i in range( self.list.GetColumnCount() ):
			self.list.SetColumnWidth( i, wx.LIST_AUTOSIZE )

	def get_icon_from_rex_object( self, pub ):
		common.dprint("publicatinos module", pub.module.lower() )
		if pub.module.lower() == 'web':
			return self.folder_w_icon
		elif pub.module.lower() == 'newsletter':
			return self.folder_n_icon
		elif pub.module.lower() == 'email':
			return self.folder_e_icon
		return -1

	def OnBeginDrag( self, event ):
		sel = common.get_selected_in_list( self.list )
		if len( sel ) < 1: return
		pid  = self.list.GetItemText( sel[0] )
		obj = self.editor.rex_object
		if obj is None: return
		data = wx.PyTextDataObject( " " )
		ds = wx.DropSource( self )
		ds.SetData( data )
		result = ds.DoDragDrop()
		if ( (wx.Platform == "__WXMSW__" ) and (result==1)) or (result == 5):
			cdom = ''
			if isinstance( self.editor.rex_object, rex.contacts.contact ):
				cdom = "<instructions><instruction action=\"%s\" publication_id=\"%s\" contact_id=%s /></instructions>" % \
				( "remove", pid, saxutils.quoteattr( obj["id"] ) )
			elif isinstance( self.editor.rex_object, rex.contacts.group ):
				cdom = "<instructions><instruction action=\"%s\" publication_id=\"%s\" group_id=\"%s\" /></instructions>" % \
				( "remove", pid, obj["id"] )
			else:
				return
			result 	= self.editor.account.execute( 'base', "subscriptions_addremove", DOM=cdom )
			if result:
				self.list.DeleteItem( sel[0] )

	def OnPublicationPaste( self, value ):
		wx.TheClipboard.Open()
		clipdata = wx.TextDataObject()
		wx.TheClipboard.GetData( clipdata )
		wx.TheClipboard.Close()
		data = clipdata.GetText()
		if data[:12]!="<publication": return
		# We are subscribing the group to a publication
		common.dprint('publication pasted')
		pub = rex.publications.publication( self.editor.account, 'web', data )
		if isinstance( self.editor.rex_object, rex.contacts.group ):
			cdom = "<instructions><instruction action=\"%s\" publication_id=\"%s\" group_id=\"%s\" /></instructions>" % \
			( self.action, pub["id"], self.editor.rex_object["id"] )
		else:
			return wx.DragNone
		result = self.editor.account.execute( 'base', "subscriptions_addremove", DOM=cdom )
		icon = self.get_icon_from_rex_object( pub )
		x = self.list.InsertImageStringItem( sys.maxint,  pub["id"], icon  )
		self.list.SetStringItem( x , 1, pub["name"] )
		self.resize_columns()

	def OnPublicationCut( self, value ):
		sel = common.get_selected_in_list( self.list )
		if len( sel ) < 1: return
		pid  = self.list.GetItemText( sel[0] )
		obj = self.editor.rex_object
		if obj is None: return
		data = wx.PyTextDataObject( " " )
		cdom = ''
		if isinstance( self.editor.rex_object, rex.contacts.contact ):
			cdom = "<instructions><instruction action=\"%s\" publication_id=\"%s\" contact_id=%s /></instructions>" % \
			( "remove", pid, saxutils.quoteattr( obj["id"] ) )
		elif isinstance( self.editor.rex_object, rex.contacts.group ):
			cdom = "<instructions><instruction action=\"%s\" publication_id=\"%s\" group_id=\"%s\" /></instructions>" % \
			( "remove", pid, obj["id"] )
		else:
			return
		result 	= self.editor.account.execute( 'base', "subscriptions_addremove", DOM=cdom )
		if result:
			self.list.DeleteItem( sel[0] )

	def OnPublicationListRightClick( self, event ):
		try:
			self.PopupMenu( self.pub_menu, wx.Point( event.m_x, event.m_y ) )
		except:
			pass

	def set_value( self, value ):
		pass

	def get_value( self ):
		pass

	def set_readwrite( self, rw ):
		pass

class subscription( sub_block_base ):
	def __init__( self, editor ):
		sub_block_base.__init__( self, editor, 'subscribe' )

class block( sub_block_base ):
	def __init__( self, editor ):
		sub_block_base.__init__( self, editor, 'block' )

class application( wx.Panel ):
	def __init__( self, editor ):
		wx.Panel.__init__( self, editor.vSplitter, -1 )
		self.editor = editor
		self.var_id = None
		# Add the subscriptions page
		sizer = wx.BoxSizer( wx.HORIZONTAL )
		self.list = wx.ListCtrl( self, style=wx.LC_REPORT )
		self.il = wx.ImageList(16, 16)
		# Load our images
		self.instance_icon 	= self.il.Add( images.getInstanceBitmap() )
		self.group_icon 	= self.il.Add( images.getGroupBitmap() )
		self.list.SetImageList( self.il, wx.IMAGE_LIST_SMALL )
		# add it
		sizer.Add( self.list, 1, wx.EXPAND)
		info = wx.ListItem()
		info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
		info.m_image = -1
		info.m_format = 0
		info.m_text = "ID"
		self.list.InsertColumnInfo(0, info)
		info.m_text = "Instance"
		self.list.InsertColumnInfo(1, info)
		if isinstance( self.editor.rex_object, rex.contacts.contact ):
			info.m_text = "Group ID"
			self.list.InsertColumnInfo(2, info)
			info.m_text = "Group Name"
			self.list.InsertColumnInfo(3, info)
		dt = sb_drop_target( self, "add", "INSTANCES" )
		self.list.SetDropTarget( dt )
		# Set the drag and drop events
		self.list.Bind( wx.EVT_LIST_BEGIN_DRAG, self.OnBeginDrag, id=self.list.GetId() )
		self.SetSizer( sizer )
		self.SetAutoLayout( 1 )
		self.Layout()
		# create the instances popup menu and hook up the events
		menu = wx.Menu()
		menu.Append( ID_INSTANCE_APPLY, "&Apply", " Apply the instance from the clipboard" )
		menu.Append( ID_INSTANCE_UNAPPLY, "&UnApply", " Unapply the selected instance" )
		self.instances_menu = menu
		self.Bind( wx.EVT_MENU, self.OnInstanceApply, id=ID_INSTANCE_APPLY )
		self.Bind( wx.EVT_MENU, self.OnInstanceUnapply, id=ID_INSTANCE_UNAPPLY )
		self.list.Bind( wx.EVT_RIGHT_DOWN, self.OnInstancesListRightClick )
		#self.list.Bind( wx.EVT_LIST_ITEM_SELECTED, self.OnInstancesItemActivated, id=ID_INSTANCES_LIST )

	def resize_columns( self ):
		'''Used internally to recalculate the column sizes'''
		# Set the column header sizes
		for i in range( self.list.GetColumnCount() ):
			self.list.SetColumnWidth( i, wx.LIST_AUTOSIZE )

	def OnInstancesListRightClick( self, event ):
		try:
			self.PopupMenu( self.instances_menu, wx.Point( event.m_x, event.m_y ) )
		except:
			pass

	#~ def OnInstancesItemActivated( self, event ):
		#~ pass

	def OnInstanceApply( self, event ):
		wx.TheClipboard.Open()
		clipdata = wx.TextDataObject()
		wx.TheClipboard.GetData( clipdata )
		wx.TheClipboard.Close()
		data = clipdata.GetText()
		tag = data.replace("[","").replace("]","")
		id_tag = ''
		name_tag = ''
		try:
			id_tag,name_tag = tag.split('|')
		except:
			common.show_error("Failed to parse instance tag")
			return
		if len( id_tag ) < 3: return
		if isinstance( self.editor.rex_object, rex.contacts.contact ):
			cdom = "<instructions><instruction action=\"%s\" contact_id=%s instance=%s /></instructions>" % \
			( 'add', saxutils.quoteattr( self.editor.rex_object["id"] ), \
			  saxutils.quoteattr( id_tag ) )
		elif isinstance( self.editor.rex_object, rex.contacts.group ):
			cdom = "<instructions><instruction action=\"%s\" group_id=\"%s\" instance=%s /></instructions>" % \
			( 'add', self.editor.rex_object["id"], saxutils.quoteattr( id_tag ) )
		else:
			return
		result = self.editor.account.execute( 'base', "instances_addremove", DOM=cdom )
		x = self.list.InsertImageStringItem( sys.maxint,  id_tag, self.instance_icon  )
		self.list.SetStringItem( x , 1, name_tag )
		item = self.list.GetItem( x )
		if isinstance( self.editor.rex_object, rex.contacts.contact ):
			self.list.SetStringItem( x , 3, 'Applied Directly' )
			self.list.SetItemBackgroundColour( x, common.sui_colors("whitesmoke") )
		self.resize_columns()

	def OnInstanceUnapply( self, event ):
		list = self.list
		sel = common.get_selected_in_list( list )
		if len( sel ) < 1: return
		tag  = list.GetItemText( sel[0] )
		obj = self.editor.rex_object
		if obj is None: return
		if isinstance( self.editor.rex_object, rex.contacts.contact ):
			cdom = "<instructions><instruction action=\"%s\" contact_id=%s instance=%s /></instructions>" % \
			( "remove", saxutils.quoteattr( self.editor.rex_object["id"] ), \
			  saxutils.quoteattr( tag ) )
		elif isinstance( self.editor.rex_object, rex.contacts.group ):
			cdom = "<instructions><instruction action=\"%s\" group_id=\"%s\" instance=%s /></instructions>" % \
			( "remove", self.editor.rex_object["id"], saxutils.quoteattr( tag ) )
		else:
			return
		result 	= self.editor.account.execute( 'base', "instances_addremove", DOM=cdom )
		if result:
			list.DeleteItem( sel[0] )

	def OnBeginDrag( self, event ):
		list = self.list
		sel = common.get_selected_in_list( list )
		if len( sel ) < 1: return
		tag  = list.GetItemText( sel[0] )

		obj = self.editor.rex_object
		if obj is None: return

		pub  = ""
		item = event.GetItem()
		if item is None: return
		pid  = list.GetItemData( sel[0] )
		if pid > 0:
			pub  = " publication=\"%s\" " % pid

		data = wx.PyTextDataObject( " " )
		ds = wx.DropSource( self )
		ds.SetData( data )
		result = ds.DoDragDrop()
		if ((wx.Platform=="__WXMSW__") and (result==1)) or (result == 5):
			if isinstance( self.editor.rex_object, rex.contacts.contact ):
				cdom = "<instructions><instruction action=\"%s\" %s contact_id=%s instance=%s /></instructions>" % \
				( "remove", pub, saxutils.quoteattr( self.editor.rex_object["id"] ), \
				  saxutils.quoteattr( tag ) )
			elif isinstance( self.editor.rex_object, rex.contacts.group ):
				cdom = "<instructions><instruction action=\"%s\" %s group_id=\"%s\" instance=%s /></instructions>" % \
				( "remove", pub, self.editor.rex_object["id"], saxutils.quoteattr( tag ) )
			else:
				return
			result 	= self.editor.account.execute( 'base', "instances_addremove", DOM=cdom )
			if result:
				list.DeleteItem( sel[0] )


	def set_value( self, value ):
		pass

	def get_value( self ):
		pass

	def set_readwrite( self, rw ):
		pass

class survey_email( wx.Panel ):
	''' Text control for editing the emails'''
	def __init__( self, parent, show_as_html = True, show_address = False ):
		self.parent = parent
		wx.Panel.__init__( self, parent, -1 )
		self.show_as_html = show_as_html
		self.show_address = show_address
		rows = 2
		growable_row = 1
		if show_address: 
			rows = rows + 1
			growable_row = growable_row + 1
		if show_as_html: rows = rows + 1
		sizer = wx.FlexGridSizer( rows, 2 )
		sizer.AddGrowableCol( 1 )
		sizer.AddGrowableRow( growable_row )
		# Email Address
		if show_address:
			sizer.Add( wx.StaticText( self, -1, "Address:", style=wx.ALIGN_RIGHT), 0, wx.EXPAND )
			self.address = wx.TextCtrl( self, ID_ADDRESS_ENTRY )
			self.address.Bind( wx.EVT_TEXT, self.OnModified )
			sizer.Add( self.address, 0, wx.EXPAND )
		# Subject
		sizer.Add( wx.StaticText( self, -1, "Subject:", style=wx.ALIGN_RIGHT), 0, wx.EXPAND )
		self.subject = wx.TextCtrl( self, ID_SUBJECT_ENTRY )
		self.subject.Bind( wx.EVT_TEXT, self.OnModified )
		sizer.Add( self.subject, 0, wx.EXPAND )
		# Body
		sizer.Add( wx.StaticText( self, -1, "Body:", style=wx.ALIGN_RIGHT), 0, wx.EXPAND | wx.NORTH, 10 )
		self.body = text( self )
		self.body.Bind( wx.stc.EVT_STC_MODIFIED, self.OnModified, id=ID_BODY_ENTRY )
		sizer.Add( self.body, 1, wx.EXPAND )
		# As HTML
		if show_as_html:
			sizer.Add( (0,0), 0 )
			self.as_html = wx.CheckBox( self, ID_HTML_CHECKBOX, "As HTML" )
			self.as_html.Bind( wx.EVT_CHECKBOX, self.AsHTMLChanged, id=ID_HTML_CHECKBOX )
			sizer.Add( self.as_html, 0 )
		self.SetSizer( sizer )
		self.SetAutoLayout( 1 )
	def set_var_dirty( self, var_id ):
		self.parent.set_var_dirty( var_id )
	def OnSave( self, event=None):
		self.parent.OnSave()
	# Set funcitons
	def SetText( self, body ):
		self.body.SetText( body )
	def SetSubject( self, subject ):
		self.subject.SetValue( subject )
	def SetHTML( self, HTML ):
		if not self.show_as_html: return
		self.as_html.SetValue( HTML=="1" )
	def SetAddress( self, address ):
		if not self.show_address: return
		self.address.SetValue( address )
	
	# Get functions
	def GetText( self ):
		return self.body.GetText()
	def GetSubject( self ):
		return self.subject.GetValue()
	def GetHTML( self ):
		if not self.show_as_html: return ""
		checked = "0"
		if self.as_html.GetValue(): checked = "1"
		return checked
	def GetAddress( self ):
		if not self.address: return ""
		return self.address.GetValue()

	def AsHTMLChanged( self, event ):
		self.OnModified( None )
		
	def OnModified( self, event ):
		# Maybe owned by something other than the notifier editor
		try: 
			if self.parent.care_about_modification:
				self.parent.SetCurrentNotifierDirty( True )
		except: pass
		
	def EmptyUndoBuffer( self ):
		pass


class questions_editor( wx.Panel ):
	def __init__( self, parent ):
		wx.Panel.__init__( self, parent.vSplitter )
		self.parent = parent
		self.kind 	= ""
		self.var_id = None
		self.p_sash_pos = self.parent.account.s4
		# a logical question type map
		self.qtype_map = []
		self.qtype_map.append( "NONE" )
		self.qtype_map.append( "TEXT" )
		self.qtype_map.append( "NOTE" )
		self.qtype_map.append( "SINGLE" )
		self.qtype_map.append( "MULTI" )
		self.qtype_map.append( "YESNO" )
		self.qtype_map.append( "LEVEL" )
		self.qtype_map.append( "LABEL" )
		self.qtype_map.append( "HEAD" )
		# this main sizer will hold everything in this panel
		hsizer = wx.BoxSizer( wx.HORIZONTAL )
		# create the main outer splitter, it splits the questions list and the right side
		self.qSplitter   = wx.SplitterWindow( self, -1, style = wx.SP_LIVE_UPDATE )
		self.qSplitter.SetMinimumPaneSize( 20 )
		# the properties splitter splits top caption part and the lower question properties panels
		self.pSplitter   = wx.SplitterWindow( self.qSplitter, -1, style = wx.SP_LIVE_UPDATE )
		self.pSplitter.SetMinimumPaneSize( 20 )
		self.pSplitter.Bind( wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged )
		# the left side panel, this holds the questions list, up/down buttons, and new/delete buttons
		self.lPanel = wx.Panel( self.qSplitter, -1 )
		# The questions List sizers
		bsizer = wx.BoxSizer( wx.HORIZONTAL )
		vsizer = wx.BoxSizer( wx.VERTICAL )
		self.list = wx.ListCtrl(self.lPanel, ID_EDITOR_LIST, style=wx.LC_REPORT | wx.LC_SINGLE_SEL )
		self.list.Bind( wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected )
		# Create the column headers
		info = wx.ListItem()
		info.m_mask 	= wx.LIST_MASK_TEXT # | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
		info.m_image 	= -1
		info.m_format 	= 0
		info.m_text 	= "#"
		self.list.InsertColumnInfo(0, info)
		info.m_text 	= "Caption"
		self.list.InsertColumnInfo(1, info)
		vsizer.Add( self.list, 1, wx.EXPAND )
		# The updown buttons
		udsizer = wx.BoxSizer( wx.HORIZONTAL )
		bmp  = images.getSmallUpArrowBitmap()
		self.up_btn   = wx.BitmapButton( self.lPanel, ID_EDITOR_QUP, bmp )
		bmp  = images.getSmallDnArrowBitmap()
		self.down_btn = wx.BitmapButton( self.lPanel, ID_EDITOR_QDOWN, bmp )
		self.up_btn.Bind( wx.EVT_BUTTON, self.OnQuestionUp )
		self.down_btn.Bind( wx.EVT_BUTTON, self.OnQuestionDown )
		udsizer.Add( self.up_btn, 1, wx.EXPAND | wx.ALL, 3 )
		udsizer.Add( self.down_btn, 1, wx.EXPAND | wx.ALL, 3 )
		# the new and delete buttons
		self.new_save_btn = wx.Button( self.lPanel, ID_EDITOR_NEW_SAVE, "New" )
		self.delete_cancel_btn = wx.Button( self.lPanel, ID_EDITOR_DELETE_CANCEL, "Cancel" )
		self.delete_cancel_btn.Enable( False )
		self.new_save_btn.Bind( wx.EVT_BUTTON, self.OnNewSave )
		self.delete_cancel_btn.Bind( wx.EVT_BUTTON, self.OnDeleteCancel )
		bsizer.Add( self.delete_cancel_btn, 1, wx.EXPAND )
		bsizer.Add( self.new_save_btn, 1, wx.EXPAND )
		vsizer.Add( udsizer, 0, wx.EXPAND )
		vsizer.Add( bsizer, 0, wx.EXPAND )
		# add the left side questions list and buttons to the left panel
		self.lPanel.SetSizer( vsizer )
		#------------#
		# Now the right side
		# the right side caption panel
		self.captionPanel = wx.Panel( self.pSplitter, -1 )
		# The caption label and the type selector
		ctsizer = wx.BoxSizer( wx.HORIZONTAL )
		self.type_selector = wx.Choice( self.captionPanel, ID_EDITOR_QTYPE, choices=["Question Type", "Text Box (single-line text entry)", "Memo (multi-line text entry)", "Single Choice", "Multiple Choice", "Yes/No", "Degree Levels", "Label", "Header"] )
		self.type_selector.Bind( wx.EVT_CHOICE, self.OnTypeChanged )
		self.type_selector.SetSelection( 0 )
		ctsizer.Add( wx.StaticText( self.captionPanel, -1, "Caption:"), 1, wx.EXPAND | wx.NORTH, 3 )
		ctsizer.Add( self.type_selector, 1, wx.EXPAND )
		# The caption editor
		self.caption = text( self, self.captionPanel )
		self.caption.Bind( wx.stc.EVT_STC_MODIFIED, self.OnCaptionModified )
		# Disable them
		self.caption.Enable( False )
		self.type_selector.Enable( False )
		# use a vertical sizer to hold the caption box and the type dropdown
		cesizer = wx.BoxSizer( wx.VERTICAL )
		cesizer.Add( ctsizer, 0, wx.EXPAND )
		cesizer.Add( self.caption, 1, wx.EXPAND | wx.ALL, 3 )
		# add the caption inputs sizer to the caption panel
		self.captionPanel.SetSizer( cesizer )
		#----------#
		# The right side bottom panel
		# the question properties will have many panels all parented by qSplitter
		self.qprops 		= {}
		self.qprops["NONE"]	= sui_question_props( self.pSplitter, "NONE" )
		self.qprops["TEXT"]	= sui_question_props( self.pSplitter, "TEXT" )
		self.qprops["NOTE"] = sui_question_props( self.pSplitter, "NOTE" )
		self.qprops["SINGLE"]=sui_question_props( self.pSplitter, "SINGLE" )
		self.qprops["MULTI"]= sui_question_props( self.pSplitter, "MULTI" )
		self.qprops["YESNO"]= sui_question_props( self.pSplitter, "YESNO" )
		self.qprops["LEVEL"]= sui_question_props( self.pSplitter, "LEVEL" )
		self.qprops["LABEL"]= sui_question_props( self.pSplitter, "LABEL" )
		self.qprops["HEAD"]	= sui_question_props( self.pSplitter, "HEAD" )
		self.SetCurrentType( "NONE" )
		self.captionPanel.Show()
		self.lPanel.Show()
		# split things up
		self.qSplitter.SplitVertically( self.lPanel, self.pSplitter )
		# add the main outer question splitter to the horizontal sizer
		hsizer.Add( self.qSplitter, 1, wx.EXPAND )
		self.qSplitter.Show()
		self.pSplitter.Show()
		# set the outer horizintal sizer as the editor sizer
		self.SetSizer( hsizer )
		self.SetAutoLayout( 1 )
		self.questions			= {}
		self.current_question 	= None
		self.current_index		= -1
		self.care_about_modification = False
	
	def OnSashChanged( self, event ):
		self.p_sash_pos = event.GetSashPosition()
		common.dprint( "saving pSplitter position", self.p_sash_pos )
		self.parent.account.s4 = self.p_sash_pos
		self.parent.account.save()

	def OnSave( self, event=None):
		self.parent.OnSave()
	
	def OnCaptionModified( self, event ):
		if( self.current_question ) and ( self.care_about_modification ):
			self.SetCurrentQuestionDirty( True )			
			
	def GetQOrder( self ):
		qdom = "<qo>"
		for i in range( 0, self.list.GetItemCount() ):
			# Set the order_index in the question
			qid = self.list.GetItemData( i )
			qn  = "<q id='%d' order_index='%d' />" % ( qid, i+1 )
			qdom = qdom + qn
		qdom = qdom + "</qo>"
		return qdom
		
	def OnQuestionUp( self, event ):
		if self.current_index < 0: return
		if self.SwapQuestions( self.current_index, self.current_index - 1 ):
			self.current_index = self.current_index - 1
			self.list.Select( self.current_index )
			common.dprint("set dirty parent class", self.parent)
			common.dprint("set dirty parent class", self.parent.__class__)
			self.parent.SetDirty( True )
			self.parent.qorder_dirty = True
			
	def OnQuestionDown( self, event ):
		if self.current_index >= self.list.GetItemCount(): return
		if self.SwapQuestions( self.current_index, self.current_index + 1 ):
			self.current_index = self.current_index + 1
			self.list.Select( self.current_index )
			self.parent.SetDirty( True )
			self.parent.qorder_dirty = True
			
	def SwapQuestions( self, index1, index2 ):
		if( index1 < 0 ) or ( index1 >= self.list.GetItemCount() ): return False
		if( index2 < 0 ) or ( index2 >= self.list.GetItemCount() ): return False
		qid1= self.list.GetItemData( index1 )
		qid2= self.list.GetItemData( index2 )
		q1 	= self.questions[ qid1 ]
		q2 	= self.questions[ qid2 ]
		self.list.SetStringItem( index2 , 1, q1["caption"] )
		self.list.SetItemData( index2, qid1 )
		self.list.SetStringItem( index1 , 1, q2["caption"] )
		self.list.SetItemData( index1, qid2 )
		self.ReOrder()
		return True
				
	def set_value( self, questions ):
		resize = False
		for q in questions:
			resize = True
			self.AppendItem( q )
		if resize: 
			self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
			self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)
		self.ReOrder()

	def set_readwrite( self, rw ):
		common.dprint("Questions editor, set readwrite: ", rw )
		
	def EmptyUndoBuffer( self ):
		pass
	
	def AppendItem( self, q ):
		x = self.list.GetItemCount()
		if( q["kind"] != "HEAD" ) and ( q["kind"] != "LABEL" ):
			self.list.InsertStringItem( x, "-" )
		else:
			self.list.InsertStringItem( x, q["order_index"] )
		self.list.SetStringItem( x , 1, q["caption"] )
		qid = int( q["id"] )
		self.questions[qid] = q
		self.list.SetItemData( x, qid )
		return x
	
	def ReOrder( self ):
		qnum = 1
		for i in range( 0, self.list.GetItemCount() ):
			# Set the order_index in the question
			qid = self.list.GetItemData( i )
			q = self.questions[ qid ]
			q["order_index"] = str( i + 1 )
			# Set the question number
			if( q["kind"] != "HEAD" ) and ( q["kind"] != "LABEL" ):
				self.list.SetItemText( i, str( qnum ) )
				qnum = qnum + 1
			else:
				self.list.SetItemText( i, "-" )
		self.list.SetColumnWidth( 0, 18 )
		self.list.SetColumnWidth( 1, wx.LIST_AUTOSIZE )
		
	def OnNewSave( self, event ):
		# Create a new Questions
		cur = wx.BusyCursor()
		self.parent.account.window.SetStatusText("Creating new question...")
		wx.Yield()
		wx.Yield()
		q = rex.forms.question( self.parent.account, self.parent.rex_object )
		q["kind"] 		= "TEXT"
		q["caption"]	= "New Question"
		q.module = self.parent.rex_object.module
		q.create()
		self.current_index 	= self.AppendItem( q )
		self.current_question = q
		self.care_about_modification = False
		self.caption.SetText( q["caption"] )
		self.list.Select( self.current_index )
		self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
		self.ClearQuestionOptions()
		self.SetCurrentType( q["kind"] )
		self.care_about_modification = True
		self.ReOrder()
		wx.Yield()
		q.save()
		wx.Yield()
		self.caption.Enable( True )
		self.type_selector.Enable( True )
		self.parent.account.window.SetStatusText("Ready")
				
	def OnDeleteCancel( self, event ):
		if not self.current_question.dirty:
			# Delete the current selected notifier
			res = wx.MessageBox( "Are you sure you want to delete this question?", "Confirm Delete", wx.YES_NO )
			if res != wx.YES: return
			cur = wx.BusyCursor()
			self.parent.account.window.SetStatusText("Creating new question...")
			wx.Yield()
			self.care_about_modification = False
			qid = int( self.current_question["id"] )
			common.dprint("About to delete the question")
			self.current_question.delete()
			common.dprint("deleted the question")
			# Remove from the list
			self.list.DeleteItem( self.current_index )
			self.questions.__delitem__( qid )
			self.current_question = None
			self.current_index    = -1
			self.caption.SetText( "" )
			self.SetCurrentType( "NONE" )
			self.delete_cancel_btn.Enable( False )
			self.caption.Enable( False )
			self.type_selector.Enable( False )
			self.ReOrder()
			self.parent.account.window.SetStatusText("Reordering questions...")
			wx.Yield()
			order = self.GetQOrder()
			self.parent.account.execute( self.parent.rex_object.module,"questions_reorder", DOM=order )
			wx.Yield()
		else:
			# Revert to the old values in the question
			self.care_about_modification = False
			self.current_question["caption"]= self.current_question.old_caption
			self.current_question["kind"] 	= self.current_question.old_kind
			self.current_question["options"] 	= self.current_question.old_data
			# Now reload the question
			self.caption.SetText( self.current_question["caption"] )
			self.qprops[ self.current_question["kind"] ].SetOptions( self.current_question["options"] )
			self.type_selector.SetSelection( self.qtype_map.index( self.current_question["kind"] ) )
			self.SetCurrentType( self.current_question["kind"] )
			# Set teh list item back
			self.list.SetStringItem( self.current_index, 1, self.current_question["caption"] )
			self.care_about_modification = True
			self.delete_cancel_btn.Enable( True )
			self.delete_cancel_btn.SetLabel( "Delete" )
			self.SetCurrentQuestionDirty( False )
		self.parent.account.window.SetStatusText("Ready")
		
	def OnItemSelected( self, event ):
		q = self.questions[event.GetItem().GetData()]
		self.current_question = q
		self.current_index    = event.GetIndex()
		common.dprint("Question Selected ", q, q.data )
		if not q.dirty:
			# Save the original values
			q.old_caption = q["caption"]
			q.old_data	  = q["options"]
			q.old_kind    = q["kind"]
			self.delete_cancel_btn.SetLabel( "Delete" )
		else:
			self.delete_cancel_btn.SetLabel( "Cancel" )
		# Load up the values
		self.care_about_modification = False
		self.caption.SetText( q["caption"] )
		wx.Yield()
		wx.Yield()
		self.qprops[ q["kind"] ].SetOptions( q["options"] )
		self.type_selector.SetSelection( self.qtype_map.index( q["kind"] ) )
		self.SetCurrentType( q["kind"] )
		self.delete_cancel_btn.Enable( True )
		self.caption.Enable( True )
		self.type_selector.Enable( True )
		self.care_about_modification = True
	
	def OnTypeChanged( self, event ):
		index = self.type_selector.GetSelection()
		self.SetCurrentType( self.qtype_map[ index ] )
		# Modify the current selected question
		if( self.current_question ) and ( self.care_about_modification ):
			self.SetCurrentQuestionDirty( True )
		
	def SetCurrentType( self, qtype ):
		for qp in self.qprops.values():
			qp.Show( False )
		# The selected question properties dialog
		qprop = self.qprops[ qtype ]
		self.pSplitter.Unsplit()
		self.pSplitter.SplitHorizontally( self.captionPanel, qprop, self.p_sash_pos )
		qprop.Show( True  )
		self.pSplitter.Show()
		self.pSplitter.Refresh()
	
	def ClearQuestionOptions( self ):
		for qp in self.qprops.values():
			qp.ClearAllOptions()
	
	def SetCurrentQuestionDirty( self, dirty ):
		self.current_question.dirty 	= dirty
		self.current_question["caption"]= self.caption.GetText()
		self.current_question["kind"] 	= self.qtype_map[ self.type_selector.GetSelection() ]
		self.current_question["options"]= self.qprops[ self.current_question["kind"] ].GetOptions()
		self.list.SetStringItem( self.current_index, 1, self.current_question["caption"] )
		if dirty:
			# TEMP
			#self.parent.SetDirty( True )
			self.delete_cancel_btn.SetLabel( "Cancel" )
		else:
			self.delete_cancel_btn.SetLabel( "Delete" )
		
class sui_question_props( wx.Panel ):
	def __init__( self, parent, kind ):
		wx.Panel.__init__( self, parent, -1 )
		self.parent = parent
		self.kind   = kind
		sizer = wx.BoxSizer( wx.VERTICAL )
		if kind == "NONE":
			sizer.Add( wx.StaticText( self, -1, "    Question type unselected"), 1, wx.EXPAND )
		elif kind == "TEXT":
			sizer.Add( wx.StaticText( self, -1, "Default value:"), 0, wx.EXPAND )
			#self.default_value = text( self.parent.GetParent().GetParent().parent, self.parent )
			self.default_value = text( self.parent.GetParent().GetParent().parent, self )
			self.default_value.Bind( wx.stc.EVT_STC_MODIFIED, self.OnModified )
			sizer.Add( self.default_value, 1, wx.EXPAND )
			sizer2 = wx.BoxSizer( wx.HORIZONTAL )
			self.numeric  = wx.CheckBox( self, -1, "Numeric"  )
			self.numeric.Bind( wx.EVT_CHECKBOX, self.OnModified )
			self.required = wx.CheckBox( self, -1, "Required" )
			self.required.Bind( wx.EVT_CHECKBOX, self.OnModified )
			sizer2.Add( self.required, 1, wx.EXPAND )
			sizer2.Add( self.numeric,  1, wx.EXPAND )
			sizer.Add( sizer2, 0, wx.EXPAND | wx.NORTH, 6 )
		elif kind == "NOTE":
			sizer.Add( wx.StaticText( self, -1, "Default value:"), 0, wx.EXPAND )
			self.default_value = text( self.parent.GetParent().GetParent().parent, self )
			self.default_value.Bind( wx.stc.EVT_STC_MODIFIED, self.OnModified )
			sizer.Add( self.default_value, 1, wx.EXPAND )
			self.required = wx.CheckBox( self, -1, "Required"  )
			self.required.Bind( wx.EVT_CHECKBOX, self.OnModified )
			sizer.Add( self.required, 0, wx.EXPAND | wx.NORTH, 6 )
		elif kind == "SINGLE":
			self.choices = sui_choice_editor( self, -1 )
			sizer.Add( self.choices, 1, wx.EXPAND )
			self.other    = wx.CheckBox( self, -1, "Include \"Other\" choice"  )
			self.other.Bind( wx.EVT_CHECKBOX, self.OnModified )
			self.required = wx.CheckBox( self, -1, "Required" )
			self.required.Bind( wx.EVT_CHECKBOX, self.OnModified )
			sizer2 = wx.BoxSizer( wx.HORIZONTAL )
			sizer2.Add( self.required, 1, wx.EXPAND )
			sizer2.Add( self.other  ,  1, wx.EXPAND )
			sizer.Add( sizer2, 0, wx.EXPAND | wx.NORTH, 6 )
		elif kind == "MULTI":
			self.choices = sui_choice_editor( self, -1 )
			sizer.Add( self.choices, 1, wx.EXPAND )
			self.other    = wx.CheckBox( self, -1, "Include \"Other\" choice"  )
			self.other.Bind( wx.EVT_CHECKBOX, self.OnModified )
			self.required = wx.CheckBox( self, -1, "Required" )
			self.required.Bind( wx.EVT_CHECKBOX, self.OnModified )
			sizer2 = wx.BoxSizer( wx.HORIZONTAL )
			sizer2.Add( self.required, 1, wx.EXPAND )
			sizer2.Add( self.other  ,  1, wx.EXPAND )
			sizer.Add( sizer2, 0, wx.EXPAND | wx.NORTH, 6 )
		elif kind == "YESNO":
			hsizer = wx.BoxSizer( wx.HORIZONTAL )
			fsizer = wx.FlexGridSizer( 3, 2 )
			fsizer.AddGrowableCol( 1 )
			#fsizer.AddGrowableRow( 1 )
			#fsizer.AddGrowableRow( 2 )
			self.checked 	= wx.RadioButton( self, -1, "Checked", style=wx.RB_GROUP )
			self.checked.Bind( wx.EVT_RADIOBUTTON, self.OnModified )
			self.unchecked 	= wx.RadioButton( self, -1, "Unchecked" )
			self.unchecked.Bind( wx.EVT_RADIOBUTTON, self.OnModified )
			self.cmeaning   = wx.TextCtrl( self, -1 )
			self.cmeaning.Bind( wx.EVT_TEXT, self.OnModified )
			self.umeaning   = wx.TextCtrl( self, -1 )
			self.umeaning.Bind( wx.EVT_TEXT, self.OnModified )
			fsizer.Add( wx.StaticText( self, -1, "Default State:"), 0, wx.EXPAND )
			fsizer.Add( wx.StaticText( self, -1, "Meaning:"), 0, wx.EXPAND )
			fsizer.Add( self.checked, 1, wx.EXPAND )
			fsizer.Add( self.cmeaning, 1, wx.EXPAND | wx.NORTH, 3 )
			fsizer.Add( self.unchecked, 1, wx.EXPAND )
			fsizer.Add( self.umeaning, 1, wx.EXPAND | wx.NORTH, 3 )
			hsizer.Add( fsizer, 1, wx.EXPAND | wx.EAST, 3 )
			
			tsizer = wx.BoxSizer( wx.VERTICAL )
			self.tnever		= wx.RadioButton( self, -1, "Never Trigger", style=wx.RB_GROUP )
			self.tnever.Bind( wx.EVT_RADIOBUTTON, self.OnModified )
			self.tchecked	= wx.RadioButton( self, -1, "When Checked" )
			self.tchecked.Bind( wx.EVT_RADIOBUTTON, self.OnModified )
			self.tunchecked	= wx.RadioButton( self, -1, "When Unchecked" )			
			self.tunchecked.Bind( wx.EVT_RADIOBUTTON, self.OnModified )
			tsizer.Add( wx.StaticText( self, -1, "Trigger When:"), 0, wx.EXPAND )
			tsizer.Add( self.tnever, 1, wx.EXPAND )
			tsizer.Add( self.tchecked, 1, wx.EXPAND )
			tsizer.Add( self.tunchecked, 1, wx.EXPAND )
			
			hsizer.Add( tsizer, 1, wx.EXPAND | wx.WEST, 3 )
			sizer.Add( hsizer, 1, wx.EXPAND )
		elif kind == "LEVEL":
			lsizer = wx.BoxSizer( wx.HORIZONTAL )
			self.left   = text( self.parent.GetParent().GetParent().parent, self )
			self.left.Bind( wx.stc.EVT_STC_MODIFIED, self.OnModified )
			self.right  = text( self.parent.GetParent().GetParent().parent, self )
			self.right.Bind( wx.stc.EVT_STC_MODIFIED, self.OnModified )
			lsizer.Add( wx.StaticText( self, -1, "Left Label:"), 0, wx.EXPAND )
			lsizer.Add( self.left, 1, wx.EXPAND )
			lsizer.Add( wx.StaticText( self, -1, "Right Label:"), 0, wx.EXPAND | wx.WEST, 5 )
			lsizer.Add( self.right, 1, wx.EXPAND )
			sizer.Add( lsizer, 1, wx.EXPAND | wx.ALL, 3 )
			
			ssizer = wx.FlexGridSizer( 2, 3, 5, 5 )
			ssizer.AddGrowableCol( 1 )
			self.lscroll = wx.ScrollBar( self, ID_EDITOR_LEVEL_SCROLL, style=wx.SB_HORIZONTAL )
			self.lscroll.Bind( wx.EVT_COMMAND_SCROLL, self.OnLevelScroll )
			self.lscroll.SetScrollbar( 0, 1, 10, 1, True )
			self.tscroll = wx.ScrollBar( self, ID_EDITOR_TRIGGER_SCROLL, style=wx.SB_HORIZONTAL )
			self.tscroll.Bind( wx.EVT_COMMAND_SCROLL, self.OnTriggerScroll )
			self.tscroll.SetScrollbar( 0, 1, 12, 1, True )
			self.llabel  = wx.StaticText( self, -1, "2")
			self.tlabel  = wx.StaticText( self, -1, "0")
			ssizer.Add( wx.StaticText( self, -1, "Levels:"), 0, wx.EXPAND )
			ssizer.Add( self.lscroll, 1, wx.EXPAND )
			ssizer.Add( self.llabel, 0, wx.EXPAND )
			ssizer.Add( wx.StaticText( self, -1, "Trigger:"), 0, wx.EXPAND )
			ssizer.Add( self.tscroll, 1, wx.EXPAND )
			ssizer.Add( self.tlabel, 0, wx.EXPAND )
			sizer.Add( ssizer, 0, wx.EXPAND| wx.NORTH | wx.EAST | wx.WEST, 5  )		
			
			self.required = wx.CheckBox( self, -1, "Required"  )
			self.required.Bind( wx.EVT_CHECKBOX, self.OnModified )
			sizer.Add( self.required, 0, wx.EXPAND | wx.NORTH, 6 )
		elif kind == "LABEL":
			sizer.Add( wx.StaticText( self, -1, "No options for Labels"), 1, wx.EXPAND )
		elif kind == "HEAD":
			sizer.Add( wx.StaticText( self, -1, "No options for Headers"), 1, wx.EXPAND )
		self.SetSizer( sizer )
		self.SetAutoLayout( 1 )
		self.Layout()
		self.care_about_modification = False
	
	def SetCurrentQuestionDirty( self, dirty ):
		try:
			#common.dprint(" editor parent ", self.parent )
			#common.dprint(" its GetParent ", self.parent.GetParent() )
			#common.dprint(" its GetParent ", self.parent.GetParent().GetParent() )
			#common.dprint(" its GetParent ", self.parent.GetParent().GetParent().parent )
			if self.parent.GetParent().GetParent().care_about_modification:
				self.parent.GetParent().GetParent().SetCurrentQuestionDirty( True )
		except:
			#common.show_error("Failed to care about modification", False)
			common.dprint("Failed to care about modification")
	
	def OnModified( self, event ):
		#~ print "> > Modified"
		self.SetCurrentQuestionDirty( True )
		
	def ClearAllOptions( self ):
		if self.kind == "TEXT":
			self.default_value.SetText( "" )
			self.required.SetValue( 0 )
			self.numeric.SetValue( 0 )
		elif self.kind == "NOTE":
			self.default_value.SetText( "" )
			self.required.SetValue( 0 )
		elif( self.kind == "SINGLE" ) or ( self.kind == "MULTI" ):
			self.choices.SetChoices( [] )
			self.required.SetValue( 0 )
			self.other.SetValue( 0 )
		elif self.kind == "LEVEL":
			self.required.SetValue( 0 )
			self.left.SetText( "" )
			self.right.SetText( "" )
			self.lscroll.SetThumbPosition( 0 )
			self.OnLevelScroll( None )
			self.tscroll.SetThumbPosition( 0 )
			self.OnTriggerScroll( None )
		elif self.kind == "YESNO":	
			self.tnever.SetValue( 1 )
			self.checked.SetValue( 1 )
			self.cmeaning.SetValue( "" )
			self.umeaning.SetValue( "" )
		
	def SetOptions( self, options ):
		self.ClearAllOptions()
		if len( options.strip() ) < 1: return
		options = common.uni2str( options )
		try:
			sdom 	= minidom.parseString( options )				
		except Exception:
			print "Failed to load quesiton options."
			return
			
		snode	= sdom.firstChild
		if snode.nodeName == "TEXT":
			required		= int( snode.getAttribute("required") )
			numeric			= int( snode.getAttribute("numeric") )
			default_value 	= common.get_node_content( snode.getElementsByTagName("default_value")[0] )
			# Set the values
			self.default_value.SetText( default_value )
			self.required.SetValue( required )
			self.numeric.SetValue( numeric )
			
		elif snode.nodeName == "NOTE":
			required		= int( snode.getAttribute("required") )
			default_value 	= common.get_node_content( snode.getElementsByTagName("default_value")[0] )
			# Set the values
			self.default_value.SetText( default_value )
			self.required.SetValue( required )
			
		elif( snode.nodeName == "SINGLE" ) or ( snode.nodeName == "MULTI" ):
			required		= int( snode.getAttribute("required") )
			other			= int( snode.getAttribute("other") )
			onodes			= snode.getElementsByTagName("options")[0].getElementsByTagName("option")
			choices			= []
			for option in onodes:
				trigger = option.getAttribute("trigger")
				choice  = common.get_node_content( option )
				c = [ choice, trigger ]
				choices.append( c )
			# Set the values
			self.choices.SetChoices( choices )
			self.required.SetValue( required )
			self.other.SetValue( other )
		
		elif snode.nodeName == "LEVEL":
			required		= int( snode.getAttribute("required") )
			left_label		= snode.getAttribute("min")
			right_label		= snode.getAttribute("max")
			level			= int( snode.getAttribute("level") )
			trigger			= int( snode.getAttribute("trigger") )
			# Set the values
			self.required.SetValue( required )
			self.left.SetText( left_label )
			self.right.SetText( right_label )
			self.lscroll.SetThumbPosition( level - 2 )
			self.OnLevelScroll( None )
			self.tscroll.SetThumbPosition( trigger )
			self.OnTriggerScroll( None )
			
		elif snode.nodeName == "YESNO":	
			onode 			= snode.getElementsByTagName("options")[0]
			default 		= int( onode.getAttribute("default") )
			trigger 		= int( onode.getAttribute("trigger") )
			cmeaning 		= onode.getAttribute("checked")
			umeaning 		= onode.getAttribute("unchecked")
			# Set the values
			trigo = [ self.tnever, self.tchecked, self.tunchecked ]
			[ t.SetValue( 0 ) for t in trigo ]
			trigo[ trigger ].SetValue( 1 )
			defo  = [ self.checked, self.unchecked ]
			[ d.SetValue( 0 ) for d in defo ]
			defo[ default ].SetValue( 1 )
			self.cmeaning.SetValue( cmeaning )
			self.umeaning.SetValue( umeaning )
			
	def GetOptions( self ):
		options = ""	
		if self.kind == "TEXT":
			default_value	= self.default_value.GetText()
			required 		= self.required.GetValue()
			numeric			= self.numeric.GetValue()
			default_value	= saxutils.quoteattr( default_value )
			default_value	= default_value[:-1][1:]
			options = "<TEXT required=\"%d\" numeric=\"%d\"><default_value>%s</default_value></TEXT>" % \
					( required, numeric, default_value )
			
		elif self.kind == "NOTE":
			default_value	= self.default_value.GetText()
			required 		= self.required.GetValue()
			default_value	= saxutils.quoteattr( default_value )
			default_value	= default_value[:-1][1:]
			options = "<NOTE required=\"%d\" ><default_value>%s</default_value></NOTE>" % \
					( required, default_value )
			
		elif( self.kind == "SINGLE" ) or ( self.kind == "MULTI" ):			
			required 		= self.required.GetValue()
			other			= self.other.GetValue()
			choices			= self.choices.GetChoices()
			options = "<%s required=\"%d\" other=\"%d\" >%s</%s>" % \
					( self.kind, required, other, choices, self.kind )
		
		elif self.kind == "LEVEL":
			required 		= self.required.GetValue()
			left_label		= saxutils.quoteattr( self.left.GetText() )
			right_label		= saxutils.quoteattr( self.right.GetText() )
			level 			= self.lscroll.GetThumbPosition() + 2
			trigger 		= self.tscroll.GetThumbPosition()			
			options = "<LEVEL required=\"%d\" level=\"%d\" trigger=\"%d\" min=%s max=%s />" % \
					( required, level, trigger, left_label, right_label )
			
		elif self.kind == "YESNO":		
			trigo = 0
			if self.tnever.GetValue(): trigo = 0
			elif self.tchecked.GetValue(): trigo = 1
			elif self.tunchecked.GetValue(): trigo = 2
			defo  = 0
			if self.unchecked.GetValue(): defo = 1
			cmeaning = saxutils.quoteattr( self.cmeaning.GetValue() )
			umeaning = saxutils.quoteattr( self.umeaning.GetValue() )
			options = "<YESNO><options default=\"%d\" checked=%s unchecked=%s trigger=\"%d\"/></YESNO>" % \
					  ( defo, cmeaning, umeaning, trigo )
		return options

	def OnLevelScroll( self, event ):
		pos = self.lscroll.GetThumbPosition()
		self.llabel.SetLabel( str( pos + 2 ) )
		tpos = self.tscroll.GetThumbPosition()
		self.tscroll.SetScrollbar( tpos, 1, pos + 3, 1, True )
		tpos = self.tscroll.GetThumbPosition()
		self.tlabel.SetLabel( str( tpos ) )
		self.SetCurrentQuestionDirty( True )
		
	def OnTriggerScroll( self, event ):
		tpos = self.tscroll.GetThumbPosition()
		self.tlabel.SetLabel( str( tpos ) )
		self.SetCurrentQuestionDirty( True )

class sui_choice_editor( wx.Panel ):
	def __init__( self, parent, id ):
		self.parent = parent
		wx.Panel.__init__( self, parent, id )
		self.kind 	= ""
		hsizer = wx.BoxSizer( wx.HORIZONTAL )
		bsizer = wx.BoxSizer( wx.HORIZONTAL )
		vsizer = wx.BoxSizer( wx.VERTICAL )
		cvsizer = wx.BoxSizer( wx.VERTICAL )
		udsizer = wx.BoxSizer( wx.VERTICAL )
		ucsizer = wx.BoxSizer( wx.HORIZONTAL )
		ltsizer = wx.BoxSizer( wx.HORIZONTAL )
		# List
		self.list = wx.ListCtrl(self, ID_EDITOR_LIST, style=wx.LC_REPORT | wx.LC_SINGLE_SEL )
		self.list.Bind( wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected )
		self.list.Bind( wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated )

		# Create the column headers
		info = wx.ListItem()
		info.m_mask 	= wx.LIST_MASK_TEXT # | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
		info.m_image 	= -1
		info.m_format 	= 0
		info.m_text 	= "Choices"
		self.list.InsertColumnInfo(0, info)
		vsizer.Add( self.list, 1, wx.EXPAND )
		
		self.new_save_btn = wx.Button( self, ID_EDITOR_NEW_SAVE, "New" )
		self.delete_cancel_btn = wx.Button( self, ID_EDITOR_DELETE_CANCEL, "Delete" )
		self.delete_cancel_btn.Enable( False )
		self.new_save_btn.Bind( wx.EVT_BUTTON, self.OnNewSave )
		self.delete_cancel_btn.Bind( wx.EVT_BUTTON,self.OnDeleteCancel )
		bsizer.Add( self.delete_cancel_btn, 1, wx.EXPAND )
		bsizer.Add( self.new_save_btn, 1, wx.EXPAND )
		vsizer.Add( bsizer, 0, wx.EXPAND )
		hsizer.Add( vsizer, 1, wx.EXPAND )
		
		# The choice properties
		ltsizer.Add( wx.StaticText( self, -1, "Choice Properties:"), 1, wx.EXPAND )
		# The trigger checkbox
		self.trigger = wx.CheckBox( self, -1, "Trigger choice" )
		ltsizer.Add( self.trigger, 1, wx.EXPAND )
		cvsizer.Add( ltsizer, 0, wx.EXPAND| wx.WEST | wx.NORTH, 3  )
		
		# The choice updown buttons
		bmp  = images.getSmallUpArrowBitmap()
		self.up_btn   = wx.BitmapButton( self, ID_EDITOR_CUP, bmp )
		bmp  = images.getSmallDnArrowBitmap()
		self.down_btn = wx.BitmapButton( self, ID_EDITOR_CDOWN, bmp )
		self.up_btn.Bind( wx.EVT_BUTTON, self.OnChoiceUp )
		self.down_btn.Bind( wx.EVT_BUTTON, self.OnChoiceDown )
		udsizer.Add( self.up_btn, 1, wx.EXPAND | wx.EAST | wx.WEST | wx.SOUTH, 5 )
		udsizer.Add( self.down_btn, 1, wx.EXPAND | wx.EAST | wx.WEST | wx.NORTH, 5 )
		ucsizer.Add( udsizer, 1, wx.EXPAND )
		# Create choice editor
		self.editor = text( self.parent )
		self.editor.Bind( wx.stc.EVT_STC_MODIFIED, self.OnOptionChanged )
		ucsizer.Add( self.editor, 8, wx.EXPAND )
		cvsizer.Add( ucsizer, 1, wx.EXPAND| wx.WEST, 3 )
		
		#ctsizer.Add( tsizer, 0, wx.EXPAND )
		hsizer.Add( cvsizer, 3, wx.EXPAND )
		
		self.SetSizer( hsizer )
		self.SetAutoLayout( 1 )
		self.choices			= []
		self.editing 			= False
		self.SetEditMode( False )
		self.current_choice 	= None
		self.current_index		= -1
		
	def OnOptionChanged( self, event ):
		if self.editing: 
			self.GetParent().SetCurrentQuestionDirty( True )
			
	def OnChoiceUp( self, event ):
		if self.current_index < 0: return
		if self.SwapChoices( self.current_index, self.current_index - 1 ):
			self.current_index = self.current_index - 1
			self.list.Select( self.current_index )
			self.GetParent().SetCurrentQuestionDirty( True )
			
	def OnChoiceDown( self, event ):
		if self.current_index >= self.list.GetItemCount(): return
		if self.SwapChoices( self.current_index, self.current_index + 1 ):
			self.current_index = self.current_index + 1
			self.list.Select( self.current_index )
			self.GetParent().SetCurrentQuestionDirty( True )
		
	def SwapChoices( self, index1, index2 ):
		if( index1 < 0 ) or ( index1 >= self.list.GetItemCount() ): return False
		if( index2 < 0 ) or ( index2 >= self.list.GetItemCount() ): return False
		choice1  = self.list.GetItemText( index1 )
		trigger1 = self.list.GetItemData( index1 )
		choice2  = self.list.GetItemText( index2 )
		trigger2 = self.list.GetItemData( index2 )
		self.list.SetItemText( index2, choice1 )
		self.list.SetItemData( index2, trigger1 )
		self.list.SetItemText( index1, choice2 )
		self.list.SetItemData( index1, trigger2 )
		return True
		
	def SetEditMode( self, editing ):
		if editing:
			self.list.Enable( False )
			self.new_save_btn.SetLabel( "Set" )
			self.delete_cancel_btn.SetLabel( "Cancel" )
			self.editor.SetReadOnly( False )
			self.trigger.Enable( True )
		else:
			self.list.Enable( True )
			self.new_save_btn.SetLabel( "New" )
			self.delete_cancel_btn.SetLabel( "Delete" )
			self.editor.SetReadOnly( True )
			self.trigger.Enable( False )
		self.editing = editing
	
	def AppendItem( self, c ):
		x = self.list.GetItemCount()
		self.list.InsertStringItem( x, c[0] )
		self.list.SetItemData( x, int( c[1] ) )
		return x
		
	def SetChoices( self, choices ):
		resize = False
		self.choices = []
		self.list.DeleteAllItems()
		for c in choices:
			resize = True
			self.AppendItem( c )
		if resize: self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
		# Clear the choice editor
		self.editor.SetReadOnly( False )
		self.editor.SetText( "" )
		self.editor.SetReadOnly( True )
			
	def GetChoices( self ):
		choices = "<options>"
		for i in range( 0, self.list.GetItemCount() ):
			#caption = self.list.GetItemText( i )
			caption = saxutils.quoteattr( self.list.GetItemText( i ) )
			caption	= caption[:-1][1:]
			trigger = self.list.GetItemData( i )
			c = "<option trigger=\"%d\">%s</option>" % ( trigger, caption )
			choices = choices + c
		choices = choices + "</options>"
		return choices
		
	def EmptyUndoBuffer( self ):
		pass
	
	def OnNewSave( self, event ):
		if self.editing:
			# Save the current choice
			if self.current_index < 0 : return
			self.list.SetItemText( self.current_index, self.editor.GetText() )
			self.list.SetItemData( self.current_index, int( self.trigger.GetValue() ) )
			self.GetParent().SetCurrentQuestionDirty( True )
		else:
			# Create a new notifier
			c = ["Choice", "0"]
			self.current_index 	= self.AppendItem( c )
			self.current_choice = c
			self.editor.SetReadOnly( False )
			self.editor.SetText( "" )
			self.list.Select( self.current_index )
			self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
			self.SetEditMode( True )
			return
		self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
		self.SetEditMode( False )
				
	def OnDeleteCancel( self, event ):
		if self.editing:
			self.editor.SetText( self.list.GetItemText( self.current_index ) )
		else:
			# Delete the current selected choice
			self.list.DeleteItem( self.current_index )
			self.current_index    = -1
			self.editor.SetReadOnly( False )
			self.editor.SetText( "" )
			self.trigger.SetValue( 0 )
			self.delete_cancel_btn.Enable( False )
			self.GetParent().SetCurrentQuestionDirty( True )
		self.SetEditMode( False )
		
	def OnItemSelected( self, event ):
		self.current_index    = event.GetIndex()
		self.editor.SetReadOnly( False )
		self.editor.SetText( self.list.GetItemText( self.current_index ) )
		self.editor.SetReadOnly( True )
		self.trigger.SetValue( self.list.GetItemData( self.current_index ) )
		self.delete_cancel_btn.Enable( True )
		
	def OnItemActivated( self, event ):
		self.SetEditMode( True )

class notifiers_editor( wx.Panel ):
	def __init__( self, parent ):
		wx.Panel.__init__( self, parent.vSplitter, -1 )
		self.parent = parent
		self.kind 	= ''
		hsizer = wx.BoxSizer( wx.HORIZONTAL )
		bsizer = wx.BoxSizer( wx.HORIZONTAL )
		vsizer = wx.BoxSizer( wx.VERTICAL )
		# List
		self.list = wx.ListCtrl(self, ID_EDITOR_LIST, style=wx.LC_REPORT | wx.LC_SINGLE_SEL )
		#self.list.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
		self.list.Bind( wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected )

		# Create the column headers
		info = wx.ListItem()
		info.m_mask 	= wx.LIST_MASK_TEXT # | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
		info.m_image 	= -1
		info.m_format 	= 0
		info.m_text 	= "Kind"
		self.list.InsertColumnInfo(0, info)
		info.m_text 	= "Notification Emails"
		self.list.InsertColumnInfo(1, info)
		vsizer.Add( self.list, 1, wx.EXPAND )
		
		self.new_save_btn = wx.Button( self, ID_EDITOR_NEW_SAVE, "New" )
		self.delete_cancel_btn = wx.Button( self, ID_EDITOR_DELETE_CANCEL, "Delete" )
		self.delete_cancel_btn.Enable( False )
		self.new_save_btn.Bind( wx.EVT_BUTTON, self.OnNewSave )
		self.delete_cancel_btn.Bind( wx.EVT_BUTTON, self.OnDeleteCancel )
		bsizer.Add( self.delete_cancel_btn, 1, wx.EXPAND )
		bsizer.Add( self.new_save_btn, 1, wx.EXPAND )
		vsizer.Add( bsizer, 0, wx.EXPAND )
		hsizer.Add( vsizer, 1, wx.EXPAND )
		
		# Create the email control
		self.email = survey_email( self, False, True )
		self.email.Enable( False )
		hsizer.Add( self.email, 5, wx.EXPAND | wx.WEST, 15 )
		
		self.SetSizer( hsizer )
		self.SetAutoLayout( 1 )
		self.notifiers			= {}
		self.current_notifier 	= None
		self.current_index		= -1
		self.care_about_modification = False
			
	def AppendItem( self, n ):
		x = self.list.GetItemCount()
		k = 'R'
		if n["kind"].lower() == 'tresp': k = 'T'
		elif n["kind"].lower() == 'cresp': k = 'C'
		self.list.InsertStringItem( x, k )
		self.list.SetStringItem( x , 1, n["email"] )
		# Add the object to the list of object to send to
		nid = int( n["id"] )
		self.notifiers[nid] = n
		self.list.SetItemData( x, nid )
		self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
		self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)
		return x
		
	def set_readwrite( self, rw ):
		pass 
		
	def set_value( self, notifiers ):
		#self.kind = ''
		resize = False
		for n in notifiers:
			resize = True
			self.AppendItem( n )
		if resize: self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
		
	def EmptyUndoBuffer( self ):
		pass
	
	def OnNewSave( self, event ):
		# Create a new notifier
		kind = "RFRL"
		if self.parent.rex_object.module.lower() == 'survey':
			# ask for the kind
			dlg = wx.SingleChoiceDialog(
                self, 'Select a Notifier Type', 'New Notifier',
                ['Completion Notifier', 'Trigger Notifier'], 
                wx.CHOICEDLG_STYLE
                )
			common.metalic( dlg )
			res = dlg.ShowModal()
			dlg.Destroy()
			if res == wx.ID_OK:
				kind = 'CRESP'
				if dlg.GetStringSelection() == 'Trigger Notifier':
					kind = 'TRESP'
			else:
				return
		n 					= rex.forms.notifier( self.parent.account, self.parent.rex_object )
		n["kind"] 			= kind
		n["survey_id"] 		= n.survey["id"]
		n["email"] 	= "notifiee@mycompany.com"
		n["email_subject"]	= "Notification"
		n["email_body"]	= "Notification"
		n.create()
		self.current_index 	= self.AppendItem( n )
		self.current_notifier = n
		self.care_about_modification = False
		self.email.SetAddress( n["email"] )
		self.email.SetSubject( n["email_subject"] )
		self.email.SetText( n["email_body"] )
		self.list.Select( self.current_index )
		self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
		self.email.Enable( True )
		self.care_about_modification = True
		
	def OnDeleteCancel( self, event ):
		if not self.current_notifier.dirty:
			# Delete the current selected notifier
			#~ print "Delete the current notifier"
			res = wx.MessageBox( "Are you sure you want to delete this notifier?", "Confirm Delete", wx.YES_NO )
			if res != wx.YES: return
			nid = int( self.current_notifier["id"] )
			self.current_notifier.delete()
			# Remove from the list
			self.list.DeleteItem( self.current_index )
			self.notifiers.__delitem__( nid )
			self.current_notifier = None
			self.current_index    = -1
			self.email.SetAddress( "" )
			self.email.SetSubject( "" )
			self.email.SetText( "" )
			self.delete_cancel_btn.Enable( False )
			self.email.Enable( False )
		else:
			# Reverto to the old values
			self.care_about_modification = False
			self.current_notifier["email"] 	= self.current_notifier.old_address
			self.current_notifier["email_subject"] 	= self.current_notifier.old_subject
			self.current_notifier["email_body"] 	= self.current_notifier.old_body
			# Reload the notifier
			self.email.SetAddress( self.current_notifier["email"] )
			self.email.SetSubject( self.current_notifier["email_subject"] )
			self.email.SetText( self.current_notifier["email_body"] )
			# Set the list item back
			self.list.SetItemText( self.current_index, self.current_notifier["email"] )
			self.care_about_modification = True
			self.delete_cancel_btn.Enable( True )
			self.delete_cancel_btn.SetLabel( "Delete" )
			self.SetCurrentNotifierDirty( False )
		
	def OnItemSelected( self, event ):
		n = self.notifiers[event.GetItem().GetData()]
		self.current_notifier = n
		self.current_index    = event.GetIndex()
		if not n.dirty:
			n.old_address 	  = n["email"]
			n.old_subject 	  = n["email_subject"]
			n.old_body  	  = n["email_body"]
			self.delete_cancel_btn.SetLabel( "Delete" )
		else:
			self.delete_cancel_btn.SetLabel( "Cancel" )
		# Load up the values
		self.care_about_modification = False
		self.email.SetAddress( n["email"] )
		self.email.SetSubject( n["email_subject"] )
		self.email.SetText( n["email_body"] )
		self.care_about_modification = True
		self.delete_cancel_btn.Enable( True )
		self.email.Enable( True )
		
	def SetCurrentNotifierDirty( self, dirty ):
		self.current_notifier.dirty 	= dirty
		self.current_notifier["email"] 	= self.email.GetAddress()
		self.current_notifier["email_subject"] 	= self.email.GetSubject()
		self.current_notifier["email_body"] 	= self.email.GetText()
		self.list.SetItemText( self.current_index, self.current_notifier["email"] )
		#~ print "Set n%s to dirty" % self.current_notifier["id"] 
		if dirty:
			self.parent.SetDirty( True )
			self.delete_cancel_btn.SetLabel( "Cancel" )
		else:
			self.delete_cancel_btn.SetLabel( "Delete" )
	
	def set_var_dirty( self, var_id ):
		self.parent.set_var_dirty( var_id )
		
	def OnSave( self, event=None):
		self.current_notifier.save()
